void *probe_signal_handler(void *arg) { probe_t *probe = (probe_t *)arg; siginfo_t siinf; sigset_t siset; #if defined(HAVE_PTHREAD_SETNAME_NP) # if defined(__APPLE__) pthread_setname_np("signal_handler"); # else pthread_setname_np(pthread_self(), "signal_handler"); # endif #endif sigemptyset(&siset); sigaddset(&siset, SIGHUP); sigaddset(&siset, SIGUSR1); sigaddset(&siset, SIGUSR2); sigaddset(&siset, SIGINT); sigaddset(&siset, SIGTERM); sigaddset(&siset, SIGQUIT); sigaddset(&siset, SIGPIPE); #if defined(__linux__) if (prctl(PR_SET_PDEATHSIG, SIGTERM) != 0) dW("prctl(PR_SET_PDEATHSIG, SIGTERM) failed"); #endif dD("Signal handler ready"); switch (errno = pthread_barrier_wait(&OSCAP_GSYM(th_barrier))) { case 0: case PTHREAD_BARRIER_SERIAL_THREAD: break; default: dE("pthread_barrier_wait: %d, %s.", errno, strerror(errno)); return (NULL); } while (sigwaitinfo(&siset, &siinf) != -1) { dD("Received signal %d from %u (%s)", siinf.si_signo, (unsigned int)siinf.si_pid, getppid() == siinf.si_pid ? "parent" : "not my parent"); #if defined(PROBE_SIGNAL_PARENTONLY) /* Listen only to signals sent from the parent process */ if (getppid() != siinf.si_pid) continue; #endif switch(siinf.si_signo) { case SIGUSR1:/* probe abort */ probe->probe_exitcode = ECONNABORTED; /* FALLTHROUGH */ case SIGINT: case SIGTERM: case SIGQUIT: case SIGPIPE: { __thr_collection coll; coll.thr = NULL; coll.cnt = 0; pthread_cancel(probe->th_input); /* collect IDs and cancel threads */ rbt_walk_inorder2(probe->workers, __abort_cb, &coll, 0); /* * Wait till all threads are canceled (they may temporarily disable * cancelability), but at most 60 seconds per thread. */ for (; coll.cnt > 0; --coll.cnt) { probe_worker_t *thr = coll.thr[coll.cnt - 1]; #if defined(HAVE_PTHREAD_TIMEDJOIN_NP) && defined(HAVE_CLOCK_GETTIME) struct timespec j_tm; if (clock_gettime(CLOCK_REALTIME, &j_tm) == -1) { dE("clock_gettime(CLOCK_REALTIME): %d, %s.", errno, strerror(errno)); continue; } j_tm.tv_sec += 60; if ((errno = pthread_timedjoin_np(thr->tid, NULL, &j_tm)) != 0) { dE("[%llu] pthread_timedjoin_np: %d, %s.", (uint64_t)thr->sid, errno, strerror(errno)); /* * Memory will be leaked here by continuing to the next thread. However, we are in the * process of shutting down the whole probe. We're just nice and gave the probe_main() * thread a chance to finish it's critical section which shouldn't take that long... */ continue; } #else if ((errno = pthread_join(thr->tid, NULL)) != 0) { dE("pthread_join: %d, %s.", errno, strerror(errno)); continue; } #endif SEAP_msg_free(coll.thr[coll.cnt - 1]->msg); oscap_free(coll.thr[coll.cnt - 1]); } oscap_free(coll.thr); goto exitloop; } case SIGUSR2: case SIGHUP: /* ignore */ break; } } exitloop: return (NULL); }
void *probe_worker_runfn(void *arg) { probe_pwpair_t *pair = (probe_pwpair_t *)arg; SEXP_t *probe_res, *obj, *oid; int probe_ret; #if defined(HAVE_PTHREAD_SETNAME_NP) pthread_setname_np(pthread_self(), "probe_worker"); #endif dD("handling SEAP message ID %u", pair->pth->sid); // probe_ret = -1; probe_res = pair->pth->msg_handler(pair->probe, pair->pth->msg, &probe_ret); // dD("handler result = %p, return code = %d", probe_res, probe_ret); /* Assuming that the red-black tree API is doing locking for us... */ if (rbt_i32_del(pair->probe->workers, pair->pth->sid, NULL) != 0) { dW("thread not found in the probe thread tree, probably canceled by an external signal"); /* * XXX: this is a possible deadlock; we can't send anything from * here because the signal handler replied to the message */ arg = NULL; SEAP_msg_free(pair->pth->msg); SEXP_free(probe_res); oscap_free(pair); return (NULL); } else { SEXP_t *items; dD("probe thread deleted"); obj = SEAP_msg_get(pair->pth->msg); oid = probe_obj_getattrval(obj, "id"); items = probe_cobj_get_items(probe_res); if (items != NULL) { SEXP_list_sort(items, SEXP_refcmp); SEXP_free(items); } if (probe_rcache_sexp_add(pair->probe->rcache, oid, probe_res) != 0) { /* TODO */ abort(); } SEXP_vfree(obj, oid, NULL); } if (probe_ret != 0) { /* * Something bad happened. A hint of the cause is stored as a error code in * probe_ret (should be). We'll send it to the library using a SEAP error packet. */ if (SEAP_replyerr(pair->probe->SEAP_ctx, pair->probe->sd, pair->pth->msg, probe_ret) == -1) { int ret = errno; dE("An error ocured while sending error status. errno=%u, %s.", errno, strerror(errno)); SEXP_free(probe_res); /* FIXME */ exit(ret); } SEXP_free(probe_res); } else { SEAP_msg_t *seap_reply; /* * OK, the probe actually returned something, let's send it to the library. */ seap_reply = SEAP_msg_new(); SEAP_msg_set(seap_reply, probe_res); if (SEAP_reply(pair->probe->SEAP_ctx, pair->probe->sd, seap_reply, pair->pth->msg) == -1) { int ret = errno; SEAP_msg_free(seap_reply); SEXP_free(probe_res); exit(ret); } SEAP_msg_free(seap_reply); SEXP_free(probe_res); } SEAP_msg_free(pair->pth->msg); oscap_free(pair->pth); oscap_free(pair); pthread_detach(pthread_self()); return (NULL); }