Search code examples
objective-cnstimercfrunloop

CFRunLoopRun() and NSTimer -> segmentation fault


Thanks in advance to anyone who is helping me.

I've a simple daemon. I allocate a class and then start a scheduled & repeating NSTimer:

[NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(usage3GviaSysctl) userInfo:nil repeats:YES];

then I call CFRunLoopRun() so that my daemon will stay alive.

int main(int argc, char *argv[])
{
   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   signal(SIGTERM, (sig_t)SIGTERM_handler);

   helper = [[NMDaemonHelper alloc] init];
   [helper startNotificationServer];
   CFRunLoopRun();

   NSLog(@"NMDAEMON: will exit");
   [pool release];
   return 0;
}

Now the problem is that after the timer fires I get a segfault. bt:

objc_msgSend
__NSFireTimer
__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__
__CFRunLoopDoTImer
__CFRunLoopRun
CFRunLoopRunSpecific

other ways to start the timer didn't work either. for example:

NSTimer *timeUpdateTimer = [[NSTimer alloc] initWithFireDate:[NSDate date] interval:1 target:self selector:@selector(usage3GviaSysctl) userInfo:nil repeats:YES]; 
[[NSRunLoop currentRunLoop] addTimer:timeUpdateTimer forMode:NSDefaultRunLoopMode];

Has anybody an idea what's going (wr)on(g)?


Solution

  • My guess is your selector doesn't have the right format ... needs to have an NSTimer argument, so your selector has to have the ":" in it, so @selector(usage3GviaSysctl:).

    ... I tried it myself and seems to works so here's my code in case it was something else:

    #import <Foundation/Foundation.h>
    
    @interface NMDaemonHelper : NSObject {
        NSTimer *_aTimer;
    }
    - (void)startNotificationServer;
    @end
    
    @implementation NMDaemonHelper
    
    - (void)dealloc {
        [_aTimer invalidate];
        [super dealloc];
    }
    
    - (void)startNotificationServer {
        _aTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(usage3GviaSysctl:) userInfo:nil repeats:YES];
    }
    
    - (void)usage3GviaSysctl:(NSTimer *)aTimer {
        NSLog(@"timer fired");
    }
    
    @end
    
    void SIGTERM_handler(int signum) {
        NSLog(@"SIGTERM_handler");
    }
    
    int main(int argc, char *argv[]) {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        signal(SIGTERM, (sig_t)SIGTERM_handler);
    
        NMDaemonHelper *helper = [[NMDaemonHelper alloc] init];
        [helper startNotificationServer];
        CFRunLoopRun();
    
        [helper release];
        NSLog(@"NMDAEMON: will exit");
        [pool release];
        return 0;
    }
    

    ... and output is:

    pho0$ ./climac
    2011-03-25 18:43:36.723 climac[2833:903] timer fired
    2011-03-25 18:43:39.723 climac[2833:903] timer fired
    2011-03-25 18:43:42.722 climac[2833:903] timer fired
    2011-03-25 18:43:45.722 climac[2833:903] timer fired
    2011-03-25 18:43:48.722 climac[2833:903] timer fired
    2011-03-25 18:43:51.722 climac[2833:903] timer fired