void uwsgi_emperor_start() { if (!uwsgi.sockets && !ushared->gateways_cnt && !uwsgi.master_process) { if (uwsgi.emperor_procname) { uwsgi_set_processname(uwsgi.emperor_procname); } uwsgi_notify_ready(); emperor_loop(); // never here exit(1); } if (uwsgi.emperor_procname) { uwsgi.emperor_pid = uwsgi_fork(uwsgi.emperor_procname); } else { uwsgi.emperor_pid = uwsgi_fork("uWSGI Emperor"); } if (uwsgi.emperor_pid < 0) { uwsgi_error("pid()"); exit(1); } else if (uwsgi.emperor_pid == 0) { #ifdef __linux__ if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { uwsgi_error("prctl()"); } #endif emperor_loop(); // never here exit(1); } }
void uwsgi_mule(int id) { int i; pid_t pid = uwsgi_fork(uwsgi.mules[id - 1].name); if (pid == 0) { #ifdef __linux__ if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { uwsgi_error("prctl()"); } #endif uwsgi.muleid = id; // avoid race conditions uwsgi.mules[id - 1].id = id; uwsgi.mules[id - 1].pid = getpid(); uwsgi_fixup_fds(0, id, NULL); uwsgi.my_signal_socket = uwsgi.mules[id - 1].signal_pipe[1]; uwsgi.signal_socket = uwsgi.shared->mule_signal_pipe[1]; uwsgi_close_all_sockets(); for (i = 0; i < 256; i++) { if (uwsgi.p[i]->master_fixup) { uwsgi.p[i]->master_fixup(1); } } for (i = 0; i < 256; i++) { if (uwsgi.p[i]->post_fork) { uwsgi.p[i]->post_fork(); } } if (uwsgi.mules[id - 1].patch) { for (i = 0; i < 256; i++) { if (uwsgi.p[i]->mule) { if (uwsgi.p[i]->mule(uwsgi.mules[id - 1].patch) == 1) { // never here break; } } } } uwsgi_mule_handler(); } else if (pid > 0) { uwsgi.mules[id - 1].id = id; uwsgi.mules[id - 1].pid = pid; uwsgi_log("spawned uWSGI mule %d (pid: %d)\n", id, (int) pid); } }
void gateway_respawn(int id) { pid_t gw_pid; struct uwsgi_gateway *ug = &ushared->gateways[id]; if (uwsgi.master_process) uwsgi.shared->gateways_harakiri[id] = 0; gw_pid = uwsgi_fork(ug->fullname); if (gw_pid < 0) { uwsgi_error("fork()"); return; } if (gw_pid == 0) { uwsgi_fixup_fds(0, 0, ug); if (uwsgi.master_as_root) uwsgi_as_root(); #ifdef __linux__ if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { uwsgi_error("prctl()"); } #endif uwsgi.mypid = getpid(); atexit(gateway_brutal_end); signal(SIGALRM, SIG_IGN); signal(SIGHUP, SIG_IGN); signal(SIGINT, end_me); signal(SIGTERM, end_me); signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, SIG_IGN); signal(SIGPIPE, SIG_IGN); signal(SIGSTOP, SIG_IGN); signal(SIGTSTP, SIG_IGN); ug->loop(id, ug->data); // never here !!! (i hope) exit(1); } ug->pid = gw_pid; ug->respawns++; if (ug->respawns == 1) { uwsgi_log("spawned %s %d (pid: %d)\n", ug->name, ug->num, (int) gw_pid); } else { uwsgi_log("respawned %s %d (pid: %d)\n", ug->name, ug->num, (int) gw_pid); } }
void uwsgi_mule(int id) { int i; pid_t pid = uwsgi_fork(uwsgi.mules[id-1].name); if (pid == 0) { uwsgi.muleid = id; // avoid race conditions uwsgi.mules[id-1].id = id; uwsgi.mules[id-1].pid = getpid(); uwsgi_fixup_fds(0, id); uwsgi.my_signal_socket = uwsgi.mules[id-1].signal_pipe[1]; uwsgi.signal_socket = uwsgi.shared->mule_signal_pipe[1]; uwsgi_close_all_sockets(); for (i = 0; i < 0xFF; i++) { if (uwsgi.p[i]->master_fixup) { uwsgi.p[i]->master_fixup(1); } } for (i = 0; i < 0xFF; i++) { if (uwsgi.p[i]->post_fork) { uwsgi.p[i]->post_fork(); } } if (uwsgi.mules[id-1].patch) { for (i = 0; i < 0xFF; i++) { if (uwsgi.p[i]->mule) { if (uwsgi.p[i]->mule(uwsgi.mules[id-1].patch) == 1) { // never here break; } } } } uwsgi_mule_handler(); } else if (pid > 0) { uwsgi.mules[id-1].id = id; uwsgi.mules[id-1].pid = pid; uwsgi_log("spawned uWSGI mule %d (pid: %d)\n", id, (int) pid); } }
pid_t spooler_start(struct uwsgi_spooler *uspool) { int i; pid_t pid = uwsgi_fork("uWSGI spooler"); if (pid < 0) { uwsgi_error("fork()"); exit(1); } else if (pid == 0) { // USR1 will be used to wake up the spooler uwsgi_unix_signal(SIGUSR1, spooler_wakeup); uwsgi.mywid = -1; uwsgi.mypid = getpid(); uspool->pid = uwsgi.mypid; // avoid race conditions !!! uwsgi.i_am_a_spooler = uspool; uwsgi_fixup_fds(0, 0, NULL); uwsgi_close_all_sockets(); for (i = 0; i < 256; i++) { if (uwsgi.p[i]->post_fork) { uwsgi.p[i]->post_fork(); } } uwsgi.signal_socket = uwsgi.shared->spooler_signal_pipe[1]; for (i = 0; i < 256; i++) { if (uwsgi.p[i]->spooler_init) { uwsgi.p[i]->spooler_init(); } } for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->spooler_init) { uwsgi.gp[i]->spooler_init(); } } spooler(uspool); } else if (pid > 0) { uwsgi_log("spawned the uWSGI spooler on dir %s with pid %d\n", uspool->dir, pid); } return pid; }
pid_t spooler_start(struct uwsgi_spooler * uspool) { int i; pid_t pid = uwsgi_fork("uWSGI spooler"); if (pid < 0) { uwsgi_error("fork()"); exit(1); } else if (pid == 0) { signal(SIGALRM, SIG_IGN); signal(SIGHUP, SIG_IGN); signal(SIGINT, end_me); signal(SIGTERM, end_me); // USR1 will be used to wake up the spooler uwsgi_unix_signal(SIGUSR1, spooler_wakeup); signal(SIGUSR2, SIG_IGN); signal(SIGPIPE, SIG_IGN); signal(SIGSTOP, SIG_IGN); signal(SIGTSTP, SIG_IGN); uwsgi.mypid = getpid(); uspool->pid = uwsgi.mypid; // avoid race conditions !!! uwsgi.i_am_a_spooler = uspool; uwsgi_fixup_fds(0, 0, NULL); uwsgi_close_all_sockets(); for (i = 0; i < 256; i++) { if (uwsgi.p[i]->post_fork) { uwsgi.p[i]->post_fork(); } } uwsgi_spooler_run(); } else if (pid > 0) { uwsgi_log("spawned the uWSGI spooler on dir %s with pid %d\n", uspool->dir, pid); } return pid; }
int uwsgi_respawn_worker(int wid) { int respawns = uwsgi.workers[wid].respawn_count; int i; if (uwsgi.threaded_logger) { pthread_mutex_lock(&uwsgi.threaded_logger_lock); } pid_t pid = uwsgi_fork(uwsgi.workers[wid].name); if (pid == 0) { signal(SIGWINCH, worker_wakeup); signal(SIGTSTP, worker_wakeup); uwsgi.mywid = wid; uwsgi.mypid = getpid(); uwsgi.workers[uwsgi.mywid].pid = uwsgi.mypid; uwsgi.workers[uwsgi.mywid].id = uwsgi.mywid; uwsgi.workers[uwsgi.mywid].harakiri = 0; uwsgi.workers[uwsgi.mywid].rss_size = 0; uwsgi.workers[uwsgi.mywid].vsz_size = 0; // do not reset worker counters on reload !!! //uwsgi.workers[uwsgi.mywid].requests = 0; // ...but maintain a delta counter (yes this is racy in multithread) uwsgi.workers[uwsgi.mywid].delta_requests = 0; //uwsgi.workers[uwsgi.mywid].failed_requests = 0; uwsgi.workers[uwsgi.mywid].respawn_count++; uwsgi.workers[uwsgi.mywid].last_spawn = uwsgi.current_time; uwsgi.workers[uwsgi.mywid].manage_next_request = 1; uwsgi.workers[uwsgi.mywid].cheaped = 0; uwsgi.workers[uwsgi.mywid].busy = 0; uwsgi.workers[uwsgi.mywid].suspended = 0; uwsgi.workers[uwsgi.mywid].sig = 0; // reset the apps count with a copy from the master uwsgi.workers[uwsgi.mywid].apps_cnt = uwsgi.workers[0].apps_cnt; uwsgi_fixup_fds(wid, 0, NULL); uwsgi.my_signal_socket = uwsgi.workers[wid].signal_pipe[1]; if (uwsgi.master_process) { if ((uwsgi.workers[uwsgi.mywid].respawn_count || uwsgi.cheap)) { for (i = 0; i < 256; i++) { if (uwsgi.p[i]->master_fixup) { uwsgi.p[i]->master_fixup(1); } } } } return 1; } else if (pid < 1) { uwsgi_error("fork()"); } else { if (respawns > 0) { uwsgi_log("Respawned uWSGI worker %d (new pid: %d)\n", wid, (int) pid); } else { uwsgi_log("spawned uWSGI worker %d (pid: %d, cores: %d)\n", wid, pid, uwsgi.cores); } } if (uwsgi.threaded_logger) { pthread_mutex_unlock(&uwsgi.threaded_logger_lock); } return 0; }
int uwsgi_respawn_worker(int wid) { int respawns = uwsgi.workers[wid].respawn_count; // we count the respawns before errors... uwsgi.workers[wid].respawn_count++; // ... same for update time uwsgi.workers[wid].last_spawn = uwsgi.current_time; // ... and memory/harakiri uwsgi.workers[wid].harakiri = 0; uwsgi.workers[wid].user_harakiri = 0; uwsgi.workers[wid].pending_harakiri = 0; uwsgi.workers[wid].rss_size = 0; uwsgi.workers[wid].vsz_size = 0; // ... reset stopped_at uwsgi.workers[wid].cursed_at = 0; uwsgi.workers[wid].no_mercy_at = 0; // internal statuses should be reset too uwsgi.workers[wid].cheaped = 0; // SUSPENSION is managed by the user, not the master... //uwsgi.workers[wid].suspended = 0; uwsgi.workers[wid].sig = 0; // this is required for various checks uwsgi.workers[wid].delta_requests = 0; int i; if (uwsgi.threaded_logger) { pthread_mutex_lock(&uwsgi.threaded_logger_lock); } pid_t pid = uwsgi_fork(uwsgi.workers[wid].name); if (pid == 0) { signal(SIGWINCH, worker_wakeup); signal(SIGTSTP, worker_wakeup); uwsgi.mywid = wid; uwsgi.mypid = getpid(); // pid is updated by the master //uwsgi.workers[uwsgi.mywid].pid = uwsgi.mypid; // OVERENGINEERING (just to be safe) uwsgi.workers[uwsgi.mywid].id = uwsgi.mywid; /* uwsgi.workers[uwsgi.mywid].harakiri = 0; uwsgi.workers[uwsgi.mywid].user_harakiri = 0; uwsgi.workers[uwsgi.mywid].rss_size = 0; uwsgi.workers[uwsgi.mywid].vsz_size = 0; */ // do not reset worker counters on reload !!! //uwsgi.workers[uwsgi.mywid].requests = 0; // ...but maintain a delta counter (yes this is racy in multithread) //uwsgi.workers[uwsgi.mywid].delta_requests = 0; //uwsgi.workers[uwsgi.mywid].failed_requests = 0; //uwsgi.workers[uwsgi.mywid].respawn_count++; //uwsgi.workers[uwsgi.mywid].last_spawn = uwsgi.current_time; uwsgi.workers[uwsgi.mywid].manage_next_request = 1; /* uwsgi.workers[uwsgi.mywid].cheaped = 0; uwsgi.workers[uwsgi.mywid].suspended = 0; uwsgi.workers[uwsgi.mywid].sig = 0; */ // reset the apps count with a copy from the master uwsgi.workers[uwsgi.mywid].apps_cnt = uwsgi.workers[0].apps_cnt; // reset wsgi_request structures for(i=0;i<uwsgi.cores;i++) { uwsgi.workers[uwsgi.mywid].cores[i].in_request = 0; memset(&uwsgi.workers[uwsgi.mywid].cores[i].req, 0, sizeof(struct wsgi_request)); } uwsgi_fixup_fds(wid, 0, NULL); uwsgi.my_signal_socket = uwsgi.workers[wid].signal_pipe[1]; if (uwsgi.master_process) { if ((uwsgi.workers[uwsgi.mywid].respawn_count || uwsgi.status.is_cheap)) { for (i = 0; i < 256; i++) { if (uwsgi.p[i]->master_fixup) { uwsgi.p[i]->master_fixup(1); } } } } return 1; } else if (pid < 1) { uwsgi_error("fork()"); } else { // the pid is set only in the master, as the worker should never use it uwsgi.workers[wid].pid = pid; if (respawns > 0) { uwsgi_log("Respawned uWSGI worker %d (new pid: %d)\n", wid, (int) pid); } else { uwsgi_log("spawned uWSGI worker %d (pid: %d, cores: %d)\n", wid, pid, uwsgi.cores); } } if (uwsgi.threaded_logger) { pthread_mutex_unlock(&uwsgi.threaded_logger_lock); } return 0; }
void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) { int devnull = -1; int throttle = 0; if (uwsgi.current_time - ud->last_spawn <= 3) { throttle = ud->respawns - (uwsgi.current_time - ud->last_spawn); } pid_t pid = uwsgi_fork("uWSGI external daemon"); if (pid < 0) { uwsgi_error("fork()"); return; } if (pid > 0) { ud->pid = pid; ud->status = 1; ud->pidfile_checks = 0; if (ud->respawns == 0) { ud->born = uwsgi_now(); } ud->respawns++; ud->last_spawn = uwsgi_now(); } else { // close uwsgi sockets uwsgi_close_all_sockets(); if (ud->daemonize) { /* refork... */ pid = fork(); if (pid < 0) { uwsgi_error("fork()"); exit(1); } if (pid != 0) { _exit(0); } uwsgi_write_pidfile(ud->pidfile); } // /dev/null will became stdin devnull = open("/dev/null", O_RDONLY); if (devnull < 0) { uwsgi_error("/dev/null open()"); exit(1); } if (devnull != 0) { if (dup2(devnull, 0)) { uwsgi_error("dup2()"); exit(1); } close(devnull); } if (setsid() < 0) { uwsgi_error("setsid()"); exit(1); } if (!ud->pidfile) { #ifdef __linux__ if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { uwsgi_error("prctl()"); } #endif } if (throttle) { uwsgi_log("[uwsgi-daemons] throttling \"%s\" for %d seconds\n", ud->command, throttle); sleep(throttle); } uwsgi_log("[uwsgi-daemons] %sspawning \"%s\"\n", ud->respawns > 0 ? "re" : "", ud->command); uwsgi_exec_command_with_args(ud->command); uwsgi_log("[uwsgi-daemons] unable to spawn \"%s\"\n", ud->command); // never here; exit(1); } return; }
void uwsgi_detach_daemons() { struct uwsgi_daemon *ud = uwsgi.daemons; while (ud) { #ifdef UWSGI_SSL // stop any legion daemon, doesn't matter if dumb or smart if (ud->pid > 0 && (ud->legion || !ud->pidfile)) { #else // stop only dumb daemons if (ud->pid > 0 && !ud->pidfile) { #endif uwsgi_log("[uwsgi-daemons] stopping daemon (pid: %d): %s\n", (int) ud->pid, ud->command); // try to stop daemon gracefully, kill it if it won't die // if mercy is not set then wait up to 3 seconds time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3); int waitpid_status; while (!kill(ud->pid, 0)) { kill(-ud->pid, ud->stop_signal); sleep(1); waitpid(-ud->pid, &waitpid_status, WNOHANG); if (uwsgi_now() >= timeout) { uwsgi_log("[uwsgi-daemons] daemon did not die in time, killing (pid: %d): %s\n", (int) ud->pid, ud->command); kill(-ud->pid, SIGKILL); break; } } // unregister daemon to prevent it from being respawned ud->registered = 0; } ud = ud->next; } } void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) { // skip unregistered daemons if (!ud->registered) return; int throttle = 0; if (uwsgi.current_time - ud->last_spawn <= 3) { throttle = ud->respawns - (uwsgi.current_time - ud->last_spawn); // if ud->respawns == 0 then we can end up with throttle < 0 if (throttle <= 0) throttle = 1; } pid_t pid = uwsgi_fork("uWSGI external daemon"); if (pid < 0) { uwsgi_error("fork()"); return; } if (pid > 0) { ud->has_daemonized = 0; ud->pid = pid; ud->status = 1; ud->pidfile_checks = 0; if (ud->respawns == 0) { ud->born = uwsgi_now(); } ud->respawns++; ud->last_spawn = uwsgi_now(); } else { // close uwsgi sockets uwsgi_close_all_sockets(); uwsgi_close_all_fds(); if (ud->gid) { if (setgid(ud->gid)) { uwsgi_error("uwsgi_spawn_daemon()/setgid()"); exit(1); } } if (ud->uid) { if (setuid(ud->uid)) { uwsgi_error("uwsgi_spawn_daemon()/setuid()"); exit(1); } } if (ud->daemonize) { /* refork... */ pid = fork(); if (pid < 0) { uwsgi_error("fork()"); exit(1); } if (pid != 0) { _exit(0); } uwsgi_write_pidfile(ud->pidfile); } if (!uwsgi.daemons_honour_stdin && !ud->honour_stdin) { // /dev/null will became stdin uwsgi_remap_fd(0, "/dev/null"); } if (setsid() < 0) { uwsgi_error("setsid()"); exit(1); } if (!ud->pidfile) { #ifdef __linux__ if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { uwsgi_error("prctl()"); } #endif } if (throttle) { uwsgi_log("[uwsgi-daemons] throttling \"%s\" for %d seconds\n", ud->command, throttle); sleep((unsigned int) throttle); } uwsgi_log("[uwsgi-daemons] %sspawning \"%s\" (uid: %d gid: %d)\n", ud->respawns > 0 ? "re" : "", ud->command, (int) getuid(), (int) getgid()); uwsgi_exec_command_with_args(ud->command); uwsgi_log("[uwsgi-daemons] unable to spawn \"%s\"\n", ud->command); // never here; exit(1); } return; } void uwsgi_opt_add_daemon(char *opt, char *value, void *none) { struct uwsgi_daemon *uwsgi_ud = uwsgi.daemons, *old_ud; char *pidfile = NULL; int daemonize = 0; int freq = 10; char *space = NULL; int stop_signal = SIGTERM; int reload_signal = 0; char *command = uwsgi_str(value); #ifdef UWSGI_SSL char *legion = NULL; if (!uwsgi_starts_with(opt, strlen(command), "legion-", 7)) { space = strchr(command, ' '); if (!space) { uwsgi_log("invalid legion daemon syntax: %s\n", command); exit(1); } *space = 0; legion = command; command = space+1; } #endif if (!strcmp(opt, "smart-attach-daemon") || !strcmp(opt, "smart-attach-daemon2") || !strcmp(opt, "legion-smart-attach-daemon") || !strcmp(opt, "legion-smart-attach-daemon2")) { space = strchr(command, ' '); if (!space) { uwsgi_log("invalid smart-attach-daemon syntax: %s\n", command); exit(1); } *space = 0; pidfile = command; // check for freq char *comma = strchr(pidfile, ','); if (comma) { *comma = 0; freq = atoi(comma + 1); } command = space + 1; if (!strcmp(opt, "smart-attach-daemon2") || !strcmp(opt, "legion-smart-attach-daemon2")) { daemonize = 1; } } if (!uwsgi_ud) { uwsgi.daemons = uwsgi_calloc(sizeof(struct uwsgi_daemon)); uwsgi_ud = uwsgi.daemons; } else { while (uwsgi_ud) { old_ud = uwsgi_ud; uwsgi_ud = uwsgi_ud->next; } uwsgi_ud = uwsgi_calloc(sizeof(struct uwsgi_daemon)); old_ud->next = uwsgi_ud; } uwsgi_ud->command = command; uwsgi_ud->pid = 0; uwsgi_ud->status = 0; uwsgi_ud->freq = freq; uwsgi_ud->registered = 0; uwsgi_ud->next = NULL; uwsgi_ud->respawns = 0; uwsgi_ud->last_spawn = 0; uwsgi_ud->daemonize = daemonize; uwsgi_ud->pidfile = pidfile; uwsgi_ud->control = 0; uwsgi_ud->stop_signal = stop_signal; uwsgi_ud->reload_signal = reload_signal; if (!strcmp(opt, "attach-control-daemon")) { uwsgi_ud->control = 1; } #ifdef UWSGI_SSL uwsgi_ud->legion = legion; #endif uwsgi.daemons_cnt++; } void uwsgi_opt_add_daemon2(char *opt, char *value, void *none) { struct uwsgi_daemon *uwsgi_ud = uwsgi.daemons, *old_ud; char *d_command = NULL; char *d_freq = NULL; char *d_pidfile = NULL; char *d_control = NULL; char *d_legion = NULL; char *d_daemonize = NULL; char *d_touch = NULL; char *d_stopsignal = NULL; char *d_reloadsignal = NULL; char *d_stdin = NULL; char *d_uid = NULL; char *d_gid = NULL; char *arg = uwsgi_str(value); if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=', "command", &d_command, "cmd", &d_command, "exec", &d_command, "freq", &d_freq, "pidfile", &d_pidfile, "control", &d_control, "daemonize", &d_daemonize, "daemon", &d_daemonize, "touch", &d_touch, "stopsignal", &d_stopsignal, "stop_signal", &d_stopsignal, "reloadsignal", &d_reloadsignal, "reload_signal", &d_reloadsignal, "stdin", &d_stdin, "uid", &d_uid, "gid", &d_gid, NULL)) { uwsgi_log("invalid --%s keyval syntax\n", opt); exit(1); } if (!d_command) { uwsgi_log("--%s: you need to specify a 'command' key\n", opt); exit(1); } #ifndef UWSGI_SSL if (d_legion) { uwsgi_log("legion subsystem is not supported on this uWSGI version, rebuild with ssl support\n"); exit(1); } #endif if (!uwsgi_ud) { uwsgi.daemons = uwsgi_calloc(sizeof(struct uwsgi_daemon)); uwsgi_ud = uwsgi.daemons; } else { while (uwsgi_ud) { old_ud = uwsgi_ud; uwsgi_ud = uwsgi_ud->next; } uwsgi_ud = uwsgi_calloc(sizeof(struct uwsgi_daemon)); old_ud->next = uwsgi_ud; } uwsgi_ud->command = d_command; uwsgi_ud->freq = d_freq ? atoi(d_freq) : 10; uwsgi_ud->daemonize = d_daemonize ? 1 : 0; uwsgi_ud->pidfile = d_pidfile; uwsgi_ud->stop_signal = d_stopsignal ? atoi(d_stopsignal) : SIGTERM; uwsgi_ud->reload_signal = d_reloadsignal ? atoi(d_reloadsignal) : 0; uwsgi_ud->control = d_control ? 1 : 0; uwsgi_ud->uid = d_uid ? atoi(d_uid) : 0; uwsgi_ud->gid = d_gid ? atoi(d_gid) : 0; uwsgi_ud->honour_stdin = d_stdin ? 1 : 0; #ifdef UWSGI_SSL uwsgi_ud->legion = d_legion; #endif if (d_touch) { size_t i,rlen = 0; char **argv = uwsgi_split_quoted(d_touch, strlen(d_touch), ";", &rlen); for(i=0;i<rlen;i++) { uwsgi_string_new_list(&uwsgi_ud->touch, argv[i]); } if (argv) free(argv); } uwsgi.daemons_cnt++; free(arg); }