Mac Writing a daemon using c/c++

Stylerxxx

macrumors newbie
Original poster
Sep 20, 2018
4
1
Hey guys,
Has anyone had an experience with porting linux daemon code to macos? I'm getting "no path for address" error in system log when the second thread start running its function loop. The daemon does not crash and even terminates properly when I kill it, but the code in the thread does not go any further. Could you advise something?

OS = Sierra 10.12.6
gcc/g++ --version = Apple LLVM version 9.0.0 (clang-900.0.39.2)

Here's the code I'm trying to make alive

Code:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <syslog.h>
#include <pthread.h>

static bool g_active = false;

void* daemon_main(void* /* ptr */) {
    unsigned int counter = 0;

    while (g_active) {
        /* !!! THE PROBLEM IS HERE !!!
         *
         * All function calls in this loop do not work,
         * but it still can quit from it, when g_active == false.
         * If I remove the loop from here, the thread will be terminated normally */

        syslog(LOG_INFO, "Counter = %d", counter++);
        sleep(2);
    }
    return nullptr;
}

void signal_handler(int signal) {
    syslog(LOG_NOTICE, "SIGTERM signal has been received. Start quitting...");

    // quit from the daemon main loop
    g_active = false;
}

int main(int argc, char** argv) {
    // our process_id and session_id
    pid_t pid, sid;

    // fork off the parent process
    pid = fork();
    if (pid < 0) {
        printf("Could not fork the PID\n");
        exit(EXIT_FAILURE);
    }

    // if we got a good pid, then we can exit the parent process
    if (pid > 0) {
        exit(EXIT_SUCCESS);
    }

    // change the file mode mask
    umask(0);

    // open any logs here
    openlog("foo", LOG_NOWAIT | LOG_PID, LOG_USER);
    syslog(LOG_NOTICE, "Logger started");

    // create a new sid for the child process
    sid = setsid();
    if (sid < 0) {
        syslog(LOG_ERR, "Could not generate session ID for child process");
        closelog();
        exit(EXIT_FAILURE);
    }

    // change the current working directory
    if ((chdir("/")) < 0) {
        syslog(LOG_ERR, "Could not change working directory to /");
        closelog();
        exit(EXIT_FAILURE);
    }

    // catch and handle signals
    if (signal(SIGTERM, signal_handler) == SIG_ERR) {
        syslog(LOG_ERR, "Could not register SIGTERM catcher");
        closelog();
        exit(EXIT_FAILURE);
    }

    // close out the standard file descriptors
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);

    // daemon-specific initialization goes here

    pthread_t secondThread;
    g_active = true;

    int ires = pthread_create(&secondThread, NULL, daemon_main, NULL);
    if (ires != 0) {
        syslog(LOG_ERR, "Could not create a second thread. Error <%d>", ires);
        closelog();
        exit(EXIT_FAILURE);
    }

    syslog(LOG_NOTICE, "Initialization completed");

    pthread_join(secondThread, NULL);

    // close system log for the child process
    syslog(LOG_NOTICE, "Successfully stopped");
    closelog();

    // terminate the child process when the daemon completes
    exit(EXIT_SUCCESS);
}
 
Last edited:

Mikael H

macrumors 6502a
Sep 3, 2014
722
352
static bool g_active = false;
while (g_active) {...}


I'm not a developer, but isn't the symptom you describe very much in accordance with the code?
 

chown33

Moderator
Staff member
Aug 9, 2009
8,785
5,171
vertical
Try putting something other than a syslog() in the thread's main loop. If that works, then at least you know the problem lies in the syslog family of functions. You could see if there are alternatives for them.


Given the fork() and the pthread_join() on the main thread, it doesn't seem like you're following the guidelines for Mac OS daemons, which is to make them compatible with launchd.
https://developer.apple.com/library...stemStartup/Chapters/CreatingLaunchdJobs.html

Many of the guidelines are under the heading "Behavior for Processes Managed by launchd". The use of fork() followed by exit() is not only not required, it actively subverts launchd. "Do not change working directory" and "Do not call setsid" are a couple of recommendations.

Another one, though not listed, would be Occam's Thread Razor: "Threads should not be multiplied beyond necessity". If the only thing your main thread is doing is waiting for a non-main thread to terminate, then you can probably just do what's on the secondary thread in the main thread.

If you really need multiple actions possibly running asynchronously, you should look at using dispatch queues:
https://developer.apple.com/documentation/DISPATCH
 
  • Like
Reactions: Stylerxxx

Stylerxxx

macrumors newbie
Original poster
Sep 20, 2018
4
1
I managed to make it work. For some reason syslog(LOG_INFO) does not print out messages to the system log, but with LOG_NOTICE it works fine. Apparently "no path for address" appears because I don't have a description of the daemon or stuff like that, I just run it as a regular executable. Gonna read carefully the docs (thanks @chown33). Well, at least it works now as expected =).
 

chown33

Moderator
Staff member
Aug 9, 2009
8,785
5,171
vertical
I managed to make it work. For some reason syslog(LOG_INFO) does not print out messages to the system log, but with LOG_NOTICE it works fine. Apparently "no path for address" appears because I don't have a description of the daemon or stuff like that, I just run it as a regular executable. Gonna read carefully the docs (thanks @chown33). Well, at least it works now as expected =).
Glad you got it working.

The LOG_NOTICE and LOG_INFO are different levels of detail. NOTICE is level 5, INFO is level 6. Only the log entries below a particular level are shown in the log. You can change the level to see more or less detail. See the man page for syslog(1).
 

okieiam

macrumors member
Dec 17, 2016
38
3
I am not a novice programmer but clang c++ thread my not fully implemented as GNU c11++
 

Stylerxxx

macrumors newbie
Original poster
Sep 20, 2018
4
1
I tend to think that this is a feature of BSD, since I got the same result on FreeBSD 11. Threads by the way work correctly in my tests.
 
  • Like
Reactions: okieiam
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.