Author: rfm
Date: Fri Mar 28 12:25:18 2014
New Revision: 37775
URL: http://svn.gna.org/viewcvs/gnustep?rev=37775&view=rev
Log:
thread-safety fix
Modified:
libs/webservices/trunk/ChangeLog
libs/webservices/trunk/GWSService.m
Modified: libs/webservices/trunk/ChangeLog
URL:
http://svn.gna.org/viewcvs/gnustep/libs/webservices/trunk/ChangeLog?rev=37775&r1=37774&r2=37775&view=diff
==============================================================================
--- libs/webservices/trunk/ChangeLog (original)
+++ libs/webservices/trunk/ChangeLog Fri Mar 28 12:25:18 2014
@@ -1,7 +1,12 @@
+2014-03-28 Richard Frith-Macdonald <[email protected]>
+
+ * GWSService.m: Fix thread safety issue when -timeout: of a request
+ is invoked and the request is still in the queue waiting to be sent.
+
2014-03-20 Richard Frith-Macdonald <[email protected]>
- GWSElement.h:
- GWSElement.m:
+ * GWSElement.h:
+ * GWSElement.m:
Change -nextElement: to traverse all nodes in tree if the requested
element name is nil.
Modified: libs/webservices/trunk/GWSService.m
URL:
http://svn.gna.org/viewcvs/gnustep/libs/webservices/trunk/GWSService.m?rev=37775&r1=37774&r2=37775&view=diff
==============================================================================
--- libs/webservices/trunk/GWSService.m (original)
+++ libs/webservices/trunk/GWSService.m Fri Mar 28 12:25:18 2014
@@ -654,6 +654,7 @@
- (void) _prepare
{
static NSData *empty = nil;
+ int stage;
NSData *req;
NSString *pm;
NSDictionary *pp;
@@ -665,6 +666,7 @@
}
[_lock lock];
+ stage = _stage;
_stage = RPCPreparing;
pm = _prepMethod;
_prepMethod = nil;
@@ -725,13 +727,18 @@
{
req = empty;
}
+ /* We must use a lock around the changes we actually make so that a
+ * call to _run: in another thread won't pick this one up prematurely.
+ */
+ [queueLock lock];
_request = [req retain];
+ _stage = stage;
+ [queueLock unlock];
}
- (void) _prepareAndRun
{
[self _prepare];
- _stage = RPCQueued;
/* Make sure that this is de-queued and run if possible.
*/
@@ -1714,7 +1721,32 @@
- (void) timeout: (NSTimer*)t
{
NSThread *cancelThread = nil;
-
+ BOOL notYetActive;
+ NSUInteger index;
+
+ /* First we check to see if the timeout occurred while the request was
+ * still in the queue (not yet active) and remove it from the queue if
+ * it did.
+ */
+ [queueLock lock];
+ index = [queued indexOfObjectIdenticalTo: self];
+ if (NSNotFound == index)
+ {
+ notYetActive = YES;
+ }
+ else
+ {
+ NSString *host = [_connectionURL host];
+
+ notYetActive = NO;
+ [queued removeObjectAtIndex: index];
+ [[queues objectForKey: host] removeObjectIdenticalTo: self];
+ }
+ [queueLock unlock];
+
+ /* Now we clean up the timer, set the request status, and initiate
+ * the cancellation of the request I/O if necessary.
+ */
[_lock lock];
if (t == _timer)
{
@@ -1729,19 +1761,26 @@
[self _setProblem: @"cancelled"];
}
_timer = nil;
- if (NO == _cancelled && NO == _completedIO)
- {
- _cancelled = YES;
- cancelThread = _ioThread;
- }
- if (nil != cancelThread)
- {
- [self performSelector: @selector(_cancel)
- onThread: cancelThread
- withObject: nil
- waitUntilDone: NO];
+ if (NO == notYetActive)
+ {
+ if (NO == _cancelled && NO == _completedIO)
+ {
+ _cancelled = YES;
+ cancelThread = _ioThread;
+ }
+ if (nil != cancelThread)
+ {
+ [self performSelector: @selector(_cancel)
+ onThread: cancelThread
+ withObject: nil
+ waitUntilDone: NO];
+ }
}
[_lock unlock];
+
+ /* Finally, if no cancellation is in progress (the request was never
+ * started or the cancellation already finished) we can handle completion.
+ */
if (nil == cancelThread)
{
[self _completed];
_______________________________________________
Gnustep-cvs mailing list
[email protected]
https://mail.gna.org/listinfo/gnustep-cvs