简体   繁体   中英

Does make any sense using cleanup code after an infinite loop?

I'm reading code for a linux daemon and its main() function is structured like this:

int main(int argc, char **argv){
  
    // code which spawns some worker threads, sets up some
    // signal handlers for clean termination, etc.
    // ...

   for(;;){ sleep(1); }

   p_clean_exit();

   return 0;
}

As it stands this makes no sense to me. The for loop will keep the process alive, waking every sencond, then going back to sleep. p_clean_exit() wil never be called nor 0 will be returned from the last statement.

Of course there's code elsewhere which sends signals, and and installed handlers which in turn call p-clen_exit() on their own for program termination. But this one instance here will never be reached. Right?

Does this make actual sense under some circumstance?

Does this make actual sense under some circumstance?

None of the code in your example really makes much sense: there's no point in writing a daemon that wakes up once per second only to sleep again without doing anything. But it's okay, because this is just a sample... it's the skeleton of a daemon, and it's understood that you'll add code inside that loop that does something interesting. The code that you add might call break or otherwise cause the loop to exit, and that's when it's good form to call p_clean_exit() .

So yes , it's true that if you were to compile and run the code as is, the call to p_clean_exit() won't mean much. But no , it's not pointless to have it there, because the whole point of the code isn't to use it as is, it's to show you how to structure a real daemon, and a real daemon should absolutely clean up after itself.

Does this make actual sense under some circumstance?

Yes, there are function macros in C and there is Duff's case machine and setjmp function call in C. There may be a call to setjmp above that executes a switch and "jumps over" the endless loop to execute cleanup code, when a longjmp is executed from some code running concurrently to the main thread.

#define p_clean_init(context)   switch (setjmp(context)) { case 0:
#define p_clean_exit()          case 1: }

jmp_buf context;
int signal_handler(...) {
    siglongjmp(context, 1);
}   
int main() {
    signal(..., signal_handler);
    p_clean_init(context);

    for(;;){ sleep(1); }

    p_clean_exit();
}

There are pthread_cleanup_push and pthread_cleanup_pop functions that are used in a similar fashion - and from documentation we know that POSIX.1 permits pthread_cleanup_push() and pthread_cleanup_pop() to be implemented as macros that expand to text containing '{' and '}' . You may explore it's glibc implementation .

Maybe worth noting: by expanding macros to a switch(...) (but also to goto with labels as values GCC extension) is explored by pthreadthread project , the method used most notably by Contiki OS. But it would not work here unless the endless loop would yield periodically.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM