cmogstored 1.8.1 - use default system stack size
[cmogstored.git] / process.c
blob2b20696bd171d4bda0108f2332c05c1d9fd61d96
1 /*
2 * Copyright (C) 2012-2020 all contributors <cmogstored-public@yhbt.net>
3 * License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
4 */
5 #include "cmogstored.h"
6 static Hash_table *processes;
8 struct worker_kill {
9 int signal;
10 unsigned count;
13 static bool process_cmp(const void *_a, const void *_b)
15 const struct mog_process *a = _a;
16 const struct mog_process *b = _b;
18 return a->pid == b->pid;
21 static size_t process_hash(const void *x, size_t tablesize)
23 const struct mog_process *p = x;
25 return p->pid % tablesize;
28 /* needed to make valgrind happy */
29 __attribute__((destructor)) static void process_atexit(void)
31 if (processes)
32 hash_free(processes);
35 /* call before forking */
36 void mog_process_init(size_t nr)
38 if (nr < 3)
39 nr = 3;
40 processes = hash_initialize(nr, NULL, process_hash, process_cmp, free);
41 mog_oom_if_null(processes);
44 void mog_process_reset(void)
46 assert(processes && "mog_process_init() never called");
47 hash_clear(processes);
50 char *mog_process_name(unsigned id)
52 char *s;
53 if (mog_process_is_worker(id))
54 return asprintf(&s, "worker[%u]", id) >= 0 ? s : 0;
56 switch (id) {
57 case MOG_PROC_UNKNOWN: return 0;
58 case MOG_PROC_IOSTAT: return strdup("iostat");
59 case MOG_PROC_UPGRADE: return strdup("upgrade");
62 return asprintf(&s, "BUG[%u]", id) >= 0 ? s : 0;
65 bool mog_process_is_worker(unsigned id)
67 switch (id) {
68 case MOG_PROC_UNKNOWN:
69 case MOG_PROC_IOSTAT:
70 case MOG_PROC_UPGRADE:
71 return false;
73 return true;
76 /* hash iterator */
77 static bool kill_worker(void *ent, void *k)
79 struct mog_process *p = ent;
80 struct worker_kill *wk = k;
82 assert(p->id != MOG_PROC_UNKNOWN &&
83 "MOG_PROC_UNKNOWN should not be registered");
85 if (!mog_process_is_worker(p->id))
86 return true;
88 wk->count++;
89 if (kill(p->pid, wk->signal) == 0)
90 return true;
93 * ESRCH: race between receiving a signal and waitpid(),
94 * ignore the error but count it, so we'lll know to wait on it.
96 if (errno != ESRCH)
97 syslog(LOG_ERR, "could not signal worker[%u] pid=%d: %m",
98 p->id, (int)p->pid);
99 return true;
103 * send signal to each worker process, returns number of processes
104 * signalled. (signal=0 counts workers registered)
106 size_t mog_kill_each_worker(int signo)
108 struct worker_kill wk = { .signal = signo, .count = 0 };
110 hash_do_for_each(processes, kill_worker, &wk);
112 return (size_t)wk.count;
115 /* Registers a process with a given id */
116 void mog_process_register(pid_t pid, unsigned id)
118 struct mog_process *p = malloc(sizeof(struct mog_process));
120 assert(id != MOG_PROC_UNKNOWN &&
121 "MOG_PROC_UNKNOWN may not be registered");
123 if (!p)
124 goto err;
126 p->pid = pid;
127 p->id = id;
129 if (hash_insert(processes, p))
130 return; /* success */
132 PRESERVE_ERRNO(free(p));
133 err:
134 syslog(LOG_ERR, "unable to register PID:%d with id=%u: %m",
135 (int)pid, id);
139 * Call on a pid after a process is reaped, returns the id of the process
140 * Returns MOG_PROC_UNKNOWN if the pid was unknown
142 unsigned mog_process_reaped(pid_t pid)
144 struct mog_process p = { .pid = pid, .id = MOG_PROC_UNKNOWN };
145 struct mog_process *r;
147 r = hash_delete(processes, &p);
148 if (r) {
149 p.id = r->id;
150 free(r);
152 return p.id;