fix mac disconnection crash due to asynchronous operations
This commit is contained in:
@@ -51,7 +51,7 @@
|
|||||||
|
|
||||||
IOBluetoothUserNotification* disconnectNotification;
|
IOBluetoothUserNotification* disconnectNotification;
|
||||||
|
|
||||||
NSMutableArray* receivedData; // a queue os NSData*
|
NSMutableArray* receivedData; // a queue of NSObject<WiiuseReceivedMessage>*
|
||||||
NSLock* receivedDataLock;
|
NSLock* receivedDataLock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,4 +66,20 @@
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@protocol WiiuseReceivedMessage <NSObject>
|
||||||
|
- (int) applyToStruct: (wiimote*) wm; // <0: not copied, 0: copied empty, >0: copied
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface WiiuseReceivedData : NSObject<WiiuseReceivedMessage> {
|
||||||
|
NSData* data;
|
||||||
|
}
|
||||||
|
- (id) initWithBytes: (void*) bytes length: (NSUInteger) length;
|
||||||
|
- (id) initWithData: (NSData*) data;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface WiiuseDisconnectionMessage : NSObject<WiiuseReceivedMessage> {
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
|||||||
@@ -142,32 +142,33 @@
|
|||||||
|
|
||||||
- (void) disconnected:(IOBluetoothUserNotification*) notification fromDevice:(IOBluetoothDevice*) device {
|
- (void) disconnected:(IOBluetoothUserNotification*) notification fromDevice:(IOBluetoothDevice*) device {
|
||||||
|
|
||||||
wiiuse_disconnected(wm);
|
WiiuseDisconnectionMessage* message = [[WiiuseDisconnectionMessage alloc] init];
|
||||||
|
[receivedDataLock lock];
|
||||||
|
[receivedData addObject:message];
|
||||||
|
[receivedDataLock unlock];
|
||||||
|
[message release];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark read, write
|
#pragma mark read, write
|
||||||
|
|
||||||
|
// <0: nothing received, else: length of data received (can be 0 in case of disconnection message)
|
||||||
- (int) checkForAvailableData {
|
- (int) checkForAvailableData {
|
||||||
unsigned int length = 0;
|
int result = -1;
|
||||||
|
|
||||||
[receivedDataLock lock];
|
[receivedDataLock lock];
|
||||||
if([receivedData count]) {
|
if([receivedData count]) {
|
||||||
// pop first item from queue
|
// look at first item in queue
|
||||||
NSData* firstData = [receivedData objectAtIndex:0];
|
NSObject<WiiuseReceivedMessage>* firstMessage = [receivedData objectAtIndex:0];
|
||||||
[receivedData removeObjectAtIndex:0];
|
result = [firstMessage applyToStruct:wm];
|
||||||
|
if(result >= 0)
|
||||||
byte* data = (byte*) [firstData bytes];
|
[receivedData removeObjectAtIndex:0];
|
||||||
length = [firstData length];
|
|
||||||
|
|
||||||
// forward event data to C struct
|
|
||||||
memcpy(wm->event_buf, data, sizeof(wm->event_buf));
|
|
||||||
}
|
}
|
||||||
[receivedDataLock unlock];
|
[receivedDataLock unlock];
|
||||||
|
|
||||||
return length;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) waitForInclomingData: (NSTimeInterval) duration {
|
- (void) waitForIncomingData: (NSTimeInterval) duration {
|
||||||
NSDate* timeoutDate = [NSDate dateWithTimeIntervalSinceNow: duration];
|
NSDate* timeoutDate = [NSDate dateWithTimeIntervalSinceNow: duration];
|
||||||
NSRunLoop *theRL = [NSRunLoop currentRunLoop];
|
NSRunLoop *theRL = [NSRunLoop currentRunLoop];
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -193,18 +194,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// result = length of data copied to event buffer
|
||||||
- (int) read {
|
- (int) read {
|
||||||
// is there already some data to read?
|
// is there already some data to read?
|
||||||
int result = [self checkForAvailableData];
|
int result = [self checkForAvailableData];
|
||||||
if(!result) {
|
if(result < 0) {
|
||||||
// wait a short amount of time, until data becomes available
|
// wait a short amount of time, until data becomes available or a timeoutis reached
|
||||||
[self waitForInclomingData:1];
|
[self waitForIncomingData:1];
|
||||||
|
|
||||||
// check again
|
// check again
|
||||||
result = [self checkForAvailableData];
|
result = [self checkForAvailableData];
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result >= 0 ? result : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int) writeBuffer: (byte*) buffer length: (NSUInteger) length {
|
- (int) writeBuffer: (byte*) buffer length: (NSUInteger) length {
|
||||||
@@ -266,7 +268,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// copy the data into the buffer
|
// copy the data into the buffer
|
||||||
NSData* newData = [[NSData alloc] initWithBytes:data length:length];
|
WiiuseReceivedData* newData = [[WiiuseReceivedData alloc] initWithBytes: data length: length];
|
||||||
[receivedDataLock lock];
|
[receivedDataLock lock];
|
||||||
[receivedData addObject: newData];
|
[receivedData addObject: newData];
|
||||||
[receivedDataLock unlock];
|
[receivedDataLock unlock];
|
||||||
@@ -275,4 +277,52 @@
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark WiiuseReceivedMessage
|
||||||
|
|
||||||
|
@implementation WiiuseReceivedData
|
||||||
|
|
||||||
|
- (id) initWithData:(NSData *)data_ {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
data = [data_ retain];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (id) initWithBytes: (void*) bytes length: (NSUInteger) length {
|
||||||
|
NSData* data_ = [[NSData alloc] initWithBytes:bytes length:length];
|
||||||
|
id result = [self initWithData: data_];
|
||||||
|
[data_ release];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc {
|
||||||
|
[data release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int) applyToStruct:(wiimote *)wm {
|
||||||
|
byte* bytes = (byte*) [data bytes];
|
||||||
|
NSUInteger length = [data length];
|
||||||
|
if(length > sizeof(wm->event_buf)) {
|
||||||
|
WIIUSE_WARNING("Received data was longer than event buffer. Dropping excess bytes.");
|
||||||
|
length = sizeof(wm->event_buf);
|
||||||
|
}
|
||||||
|
memcpy(wm->event_buf, bytes, length);
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation WiiuseDisconnectionMessage
|
||||||
|
|
||||||
|
- (int) applyToStruct:(wiimote *)wm {
|
||||||
|
wiiuse_disconnected(wm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
|||||||
@@ -149,13 +149,14 @@ int wiiuse_os_poll(struct wiimote_t** wm, int wiimotes) {
|
|||||||
if (wiiuse_os_read(wm[i])) {
|
if (wiiuse_os_read(wm[i])) {
|
||||||
/* propagate the event, messages should be read as in linux, starting from the second element */
|
/* propagate the event, messages should be read as in linux, starting from the second element */
|
||||||
propagate_event(wm[i], wm[i]->event_buf[1], wm[i]->event_buf+2);
|
propagate_event(wm[i], wm[i]->event_buf[1], wm[i]->event_buf+2);
|
||||||
evnt += (wm[i]->event != WIIUSE_NONE);
|
|
||||||
|
|
||||||
/* clear out the event buffer */
|
/* clear out the event buffer */
|
||||||
memset(wm[i]->event_buf, 0, sizeof(wm[i]->event_buf));
|
memset(wm[i]->event_buf, 0, sizeof(wm[i]->event_buf));
|
||||||
} else {
|
} else {
|
||||||
idle_cycle(wm[i]);
|
idle_cycle(wm[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
evnt += (wm[i]->event != WIIUSE_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return evnt;
|
return evnt;
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ void wiiuse_cleanup(struct wiimote_t** wm, int wiimotes) {
|
|||||||
|
|
||||||
for (; i < wiimotes; ++i) {
|
for (; i < wiimotes; ++i) {
|
||||||
wiiuse_disconnect(wm[i]);
|
wiiuse_disconnect(wm[i]);
|
||||||
|
wiiuse_cleanup_platform_fields(wm[i]);
|
||||||
free(wm[i]);
|
free(wm[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,8 +178,6 @@ void wiiuse_disconnected(struct wiimote_t* wm) {
|
|||||||
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_CONNECTED);
|
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_CONNECTED);
|
||||||
|
|
||||||
/* reset a bunch of stuff */
|
/* reset a bunch of stuff */
|
||||||
wiiuse_cleanup_platform_fields(wm);
|
|
||||||
|
|
||||||
wm->leds = 0;
|
wm->leds = 0;
|
||||||
wm->state = WIIMOTE_INIT_STATES;
|
wm->state = WIIMOTE_INIT_STATES;
|
||||||
wm->read_req = NULL;
|
wm->read_req = NULL;
|
||||||
|
|||||||
Reference in New Issue
Block a user