bugGNUstep - Bugs: bug #40612, NSTaskDidTerminateNotification...

Group
 
 

bug #40612: NSTaskDidTerminateNotification posted late or never

Submitter:  Larry Campbell <lcampbel>
Submitted:  Sun 17 Nov 2013 09:09:25 PM UTC
   
 
Category:  Base/Foundation Severity:  3 - Normal
Item Group:  None Status:  Ready For Test
Privacy:  Public Assigned to:  None
Open/Closed:  In Test
* Mandatory Fields

Add a New Comment Rich Markup
   

Fri 20 Dec 2013 02:48:06 PM UTC, comment #3: 

Thanks … the patch wasn't attached separately and wouldn't apply using cut and paste from the web page, so I implemented something that looked like it did the right thing.

I'm not sure exactly what the test code was supposed to do, so I wrapped it in a file in the testsuite (Tests/base/NSTask/notify.m), changing the subtask to be portable rather than unix-specific.

Please could you:
a. try it out and
b. update notify.m to act as a proper regression test which passes when the behavior is correct.

Richard Frith-Macdonald <CaS>
Group Member
Sun 17 Nov 2013 09:12:22 PM UTC, comment #2: 

The following test function works on Mac OS X, but fails with gnustep without the fixes:


static BOOL taskTerminationNotificationReceived;

- (void)taskDidTerminate:(NSNotification *)notification
{
    NSLog(@"Received NSTaskDidTerminateNotification %@", notification);
    taskTerminationNotificationReceived = YES;
}

- (void)testNSTaskNotifications
{
    NSDate *deadline;
    BOOL earlyTermination = NO;

    for (;;) {
        NSTask *task = [NSTask new];
        [task setLaunchPath:@"/bin/sh"];
        [task setArguments:[NSArray arrayWithObjects:@"-c", @"echo Child starting; sleep 10; echo Child exiting", nil]];
taskTerminationNotificationReceived = NO;
        [[NSNotificationCenter defaultCenter] addObserver: self
                                                 selector: @selector(taskDidTerminate:)
                                                     name: NSTaskDidTerminateNotification
                                                   object: task];
        [task launch];
        NSLog(@"Launched pid %d", [task processIdentifier]);
        if (earlyTermination) {
            NSLog(@"Running run loop for 5 seconds");
            deadline = [NSDate dateWithTimeIntervalSinceNow:5.0];
            while ([deadline timeIntervalSinceNow] > 0.0)
                [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
            NSLog(@"Run loop finished, will now call -[NSTask terminate]");
            [task terminate];
            NSLog(@"Terminate returned, waiting for termination");
            [task waitUntilExit];
        } else {
            NSLog(@"Running run loop for 15 seconds");
            deadline = [NSDate dateWithTimeIntervalSinceNow:15.0];
            while ([deadline timeIntervalSinceNow] > 0.0 && !taskTerminationNotificationReceived)
                [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
        }
        [task release];
        NSAssert(taskTerminationNotificationReceived, @"termination notification not received");
        [[NSNotificationCenter defaultCenter] removeObserver:self name:NSTaskDidTerminateNotification object:nil];
        if (earlyTermination)
            break;
        earlyTermination = YES;
    }
}

Larry Campbell <lcampbel>
Sun 17 Nov 2013 09:10:51 PM UTC, comment #1: 

Fixes (based on gnustep 1.24.0):

* NSRunLoop.m.orig Sun Nov 17 19:48:08 2013
--- NSRunLoop.m Sun Nov 17 20:03:44 2013
*************
* 1240,1245 **
--- 1240,1248 ----
 
    NSAssert(mode != nil, NSInvalidArgumentException);
 
+   GSPrivateCheckTasks();
+   GSPrivateNotifyASAP(mode);
+
    /* Find out how long we can wait before first limit date. */
    d = [self limitDateForMode: mode];
    if (d == nil)



* NSTask.m.orig Sun Nov 17 18:18:09 2013
--- NSTask.m Sun Nov 17 20:47:04 2013
*************
* 855,862 **
  - (void) waitUntilExit
  {
    NSTimer *timer = nil;
 
!   while ([self isRunning])
      {
        NSDate *limit;
 
--- 855,865 ----
  - (void) waitUntilExit
  {
    NSTimer *timer = nil;
+   int extra = 1; // call run loop once more after termination so notifications are posted promptly
 
!   IF_NO_GC([[self retain] autorelease];) // in case notification releases self
!
!   while ([self isRunning] || extra-- > 0)
      {
        NSDate *limit;

Larry Campbell <lcampbel>
Sun 17 Nov 2013 09:09:25 PM UTC, original submission:  

NSTaskDidTerminateNotification is sometimes posted late or never. It is not posted if the current run loop has no input sources or timers. On Mac OS X, it is posted regardless of whether the run loop has input sources or timers. Further, on Mac OS X if you call -[NSTask waitUntilExit] your notifications will be posted before waitUntilExit returns; on gnustep it will only be posted later (the next time a run loop with timers or input sources is entered).

Larry Campbell <lcampbel>

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

No files currently attached

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by CaS (Posted a comment)
  • -email is unavailable- added by lcampbel (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only logged-in users can vote.

     

    Follow 2 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2013-12-20 CaS StatusNone Ready For Test
        Open/ClosedOpen In Test

    Back to the top

    Powered by Savane 3.13-4448.
    Corresponding source code