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

Reply via email to