fix mac disconnection crash due to asynchronous operations

This commit is contained in:
Lysann Schlegel
2012-11-11 18:44:31 +01:00
parent 9892efab93
commit 3b1d440f03
4 changed files with 88 additions and 22 deletions

View File

@@ -51,7 +51,7 @@
IOBluetoothUserNotification* disconnectNotification;
NSMutableArray* receivedData; // a queue os NSData*
NSMutableArray* receivedData; // a queue of NSObject<WiiuseReceivedMessage>*
NSLock* receivedDataLock;
}
@@ -66,4 +66,20 @@
@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__

View File

@@ -142,32 +142,33 @@
- (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
// <0: nothing received, else: length of data received (can be 0 in case of disconnection message)
- (int) checkForAvailableData {
unsigned int length = 0;
int result = -1;
[receivedDataLock lock];
if([receivedData count]) {
// pop first item from queue
NSData* firstData = [receivedData objectAtIndex:0];
[receivedData removeObjectAtIndex:0];
byte* data = (byte*) [firstData bytes];
length = [firstData length];
// forward event data to C struct
memcpy(wm->event_buf, data, sizeof(wm->event_buf));
// look at first item in queue
NSObject<WiiuseReceivedMessage>* firstMessage = [receivedData objectAtIndex:0];
result = [firstMessage applyToStruct:wm];
if(result >= 0)
[receivedData removeObjectAtIndex:0];
}
[receivedDataLock unlock];
return length;
return result;
}
- (void) waitForInclomingData: (NSTimeInterval) duration {
- (void) waitForIncomingData: (NSTimeInterval) duration {
NSDate* timeoutDate = [NSDate dateWithTimeIntervalSinceNow: duration];
NSRunLoop *theRL = [NSRunLoop currentRunLoop];
while (true) {
@@ -193,18 +194,19 @@
}
}
// result = length of data copied to event buffer
- (int) read {
// is there already some data to read?
int result = [self checkForAvailableData];
if(!result) {
// wait a short amount of time, until data becomes available
[self waitForInclomingData:1];
if(result < 0) {
// wait a short amount of time, until data becomes available or a timeoutis reached
[self waitForIncomingData:1];
// check again
result = [self checkForAvailableData];
}
return result;
return result >= 0 ? result : 0;
}
- (int) writeBuffer: (byte*) buffer length: (NSUInteger) length {
@@ -266,7 +268,7 @@
}
// copy the data into the buffer
NSData* newData = [[NSData alloc] initWithBytes:data length:length];
WiiuseReceivedData* newData = [[WiiuseReceivedData alloc] initWithBytes: data length: length];
[receivedDataLock lock];
[receivedData addObject: newData];
[receivedDataLock unlock];
@@ -275,4 +277,52 @@
@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__

View File

@@ -149,13 +149,14 @@ int wiiuse_os_poll(struct wiimote_t** wm, int wiimotes) {
if (wiiuse_os_read(wm[i])) {
/* 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);
evnt += (wm[i]->event != WIIUSE_NONE);
/* clear out the event buffer */
memset(wm[i]->event_buf, 0, sizeof(wm[i]->event_buf));
} else {
idle_cycle(wm[i]);
}
evnt += (wm[i]->event != WIIUSE_NONE);
}
return evnt;

View File

@@ -85,6 +85,7 @@ void wiiuse_cleanup(struct wiimote_t** wm, int wiimotes) {
for (; i < wiimotes; ++i) {
wiiuse_disconnect(wm[i]);
wiiuse_cleanup_platform_fields(wm[i]);
free(wm[i]);
}
@@ -177,8 +178,6 @@ void wiiuse_disconnected(struct wiimote_t* wm) {
WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_CONNECTED);
/* reset a bunch of stuff */
wiiuse_cleanup_platform_fields(wm);
wm->leds = 0;
wm->state = WIIMOTE_INIT_STATES;
wm->read_req = NULL;