Annotation of freem/src/jobtab.c, revision 1.7
1.1 snw 1: /*
1.7 ! snw 2: * $Id: jobtab.c,v 1.6 2025/04/10 01:24:38 snw Exp $
1.1 snw 3: * job table implementation
4: *
5: *
1.3 snw 6: * Author: Serena Willis <snw@coherent-logic.com>
1.1 snw 7: * Copyright (C) 1998 MUG Deutschland
1.4 snw 8: * Copyright (C) 2021, 2023, 2025 Coherent Logic Development LLC
1.1 snw 9: *
10: *
11: * This file is part of FreeM.
12: *
13: * FreeM is free software: you can redistribute it and/or modify
14: * it under the terms of the GNU Affero Public License as published by
15: * the Free Software Foundation, either version 3 of the License, or
16: * (at your option) any later version.
17: *
18: * FreeM is distributed in the hope that it will be useful,
19: * but WITHOUT ANY WARRANTY; without even the implied warranty of
20: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21: * GNU Affero Public License for more details.
22: *
23: * You should have received a copy of the GNU Affero Public License
24: * along with FreeM. If not, see <https://www.gnu.org/licenses/>.
25: *
1.5 snw 26: * $Log: jobtab.c,v $
1.7 ! snw 27: * Revision 1.6 2025/04/10 01:24:38 snw
! 28: * Remove C++ style comments
! 29: *
1.6 snw 30: * Revision 1.5 2025/03/24 02:57:49 snw
31: * Shared memory compatibility fixes for OS/2
32: *
1.5 snw 33: * Revision 1.4 2025/03/09 19:14:25 snw
34: * First phase of REUSE compliance and header reformat
35: *
1.4 snw 36: *
37: * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
38: * SPDX-License-Identifier: AGPL-3.0-or-later
1.1 snw 39: **/
40: #include <stdlib.h>
41: #include <string.h>
42: #include <time.h>
43: #include <unistd.h>
1.7 ! snw 44: #include <errno.h>
1.1 snw 45:
46: #include "mpsdef.h"
47: #include "shmmgr.h"
48: #include "jobtab.h"
1.7 ! snw 49: #include "log.h"
1.1 snw 50:
1.5 snw 51: #if !defined(__OpenBSD__) && !defined(__APPLE__) && !defined(__OS2__)
1.1 snw 52: union semun {
53: int val; /* Value for SETVAL */
54: struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
55: unsigned short *array; /* Array for GETALL, SETALL */
56: struct seminfo *__buf; /* Buffer for IPC_INFO
57: (Linux-specific) */
58: };
59: #endif
60:
61: int semid_jobtab;
62: short have_jobtab_sem = FALSE;
63:
64: void jobtab_init(void)
65: {
66: union semun arg;
67: key_t jt_sk;
68:
69: jt_sk = ftok (config_file, 2);
70: if (first_process) {
71:
72: semid_jobtab = semget (jt_sk, 1, 0666 | IPC_CREAT);
73: if (semid_jobtab == -1) {
1.7 ! snw 74: logprintf (FM_LOG_FATAL, "jobtab_init: failed to create job table semaphore (error code %d [%s])", errno, strerror (errno));
1.1 snw 75: }
76: else {
1.7 ! snw 77: logprintf (FM_LOG_INFO, "jobtab_init: job table semaphore created with semid %d", semid_jobtab);
1.1 snw 78: }
79:
80: arg.val = 1;
81: if (semctl (semid_jobtab, 0, SETVAL, arg) == -1) {
1.7 ! snw 82: logprintf (FM_LOG_FATAL, "jobtab_init: failed to initialize job table semaphore (error code %d [%s])", errno, strerror (errno));
1.1 snw 83: }
84: else {
1.7 ! snw 85: logprintf (FM_LOG_INFO, "jobtab_init: job table semaphore initialized");
1.1 snw 86: }
87:
88: }
89: else {
90:
91: semid_jobtab = semget (jt_sk, 1, 0);
92: if (semid_jobtab == -1) {
1.7 ! snw 93: logprintf (FM_LOG_FATAL, "jobtab_init: could not attach to job table semaphore (error code %d [%s])", errno, strerror (errno));
! 94: }
! 95: else {
! 96: logprintf (FM_LOG_INFO, "jobtab_init: attached to job table semaphore (semid %d)", semid_jobtab);
1.1 snw 97: }
98:
99: }
100:
101: return;
102: }
103:
104: short jobtab_get_sem(void)
105: {
106: int tries;
107: struct sembuf s = {0, -1, IPC_NOWAIT};
108:
109: if (have_jobtab_sem) {
110: return TRUE;
111: }
112:
113: for (tries = 0; tries < 5; tries++) {
114:
115: if (semop (semid_jobtab, &s, 1) != -1) {
116: have_jobtab_sem = TRUE;
117: return TRUE;
118: }
119:
1.7 ! snw 120: logprintf (FM_LOG_WARNING, "jobtab_get_sem: sleeping for retry [tries = %d]", tries);
1.1 snw 121: sleep (1);
122:
123: }
1.7 ! snw 124: logprintf (FM_LOG_ERROR, "jobtab_get_sem: failed to acquire job table semaphore");
1.1 snw 125:
126: have_jobtab_sem = FALSE;
127: return FALSE;
128: }
129:
130: void jobtab_release_sem(void)
131: {
132: struct sembuf s = {0, 1, 0};
133:
134: semop (semid_jobtab, &s, 1);
135:
136: have_jobtab_sem = FALSE;
137: }
138:
139:
140: job_slot_t *job_init(short is_fmadm)
141: {
142:
143: job_slot_t *s;
144:
145: if (jobtab_get_sem () == FALSE) {
1.7 ! snw 146: logprintf (FM_LOG_FATAL, "job_init: failed to get job table semaphore");
1.1 snw 147: }
148:
149: for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
150:
151: if (((s->flags & JFLG_DEFUNCT) == JFLG_DEFUNCT) || (s->pid == pid)) {
152: goto skip_alloc;
153: }
154:
155: }
156:
157: s = (job_slot_t *) shm_alloc (sizeof (job_slot_t));
158: NULLPTRCHK(s,"job_init");
159:
160:
161: skip_alloc:
162:
163: s->pid = pid;
164: s->ipc_head = (ipc_slot_t *) NULL;
165: s->status = JSTAT_IDLE;
166: s->start_time = time (NULL);
167: s->stop_requested = 0;
168:
169: if (first_process) {
170: s->flags = JFLG_DAEMON | JFLG_NEW;
171: }
172: else {
173: if (is_fmadm == TRUE) {
174: s->flags = JFLG_NEW | JFLG_FMADM;
175: }
176: else {
177: s->flags = JFLG_NEW;
178: }
179: }
180:
181: s->next = shm_config->hdr->jobtab_head;
182: shm_config->hdr->jobtab_head = s;
183:
184: jobtab_release_sem ();
185:
186: return s;
187:
188: }
189:
190: void job_remove(const pid_t pid)
191: {
192:
193: job_slot_t *t = shm_config->hdr->jobtab_head;
194: job_slot_t *p = NULL;
195:
1.7 ! snw 196: if (jobtab_get_sem () == FALSE) {
! 197: logprintf (FM_LOG_FATAL, "job_remove: failed to get job table semaphore");
1.1 snw 198: exit (1);
199: }
200:
201: if ((t != (job_slot_t *) NULL) && (t->pid == pid)) {
202:
203: shm_config->hdr->jobtab_head = t->next;
204: shm_free (t);
205:
206: jobtab_release_sem ();
207:
208: return;
209:
210: }
211:
212: while ((t != NULL) && (t->pid != pid)) {
213: p = t;
214: t = t->next;
215: }
216:
217: if (t == NULL) {
218: jobtab_release_sem ();
219: return;
220: }
221:
222: p->next = t->next;
223: shm_free (t);
224:
225: jobtab_release_sem ();
226:
227: }
228:
229: void job_request_stop(const pid_t target_pid)
230: {
231:
232: job_slot_t *s;
233:
234: if (jobtab_get_sem() == FALSE) {
1.7 ! snw 235: logprintf (FM_LOG_FATAL, "job_request_stop: failed to get job table semaphore");
1.1 snw 236: }
237:
238: for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
239:
240: if (s->pid == target_pid) {
241: s->stop_requested = pid;
242:
243: jobtab_release_sem ();
244: job_set_status (target_pid, JSTAT_SHUTDOWN);
245:
246: return;
247: }
248:
249: }
250:
251: jobtab_release_sem ();
252:
253: }
254:
255: void job_set_ecode(const pid_t target_pid, const char *ecode)
256: {
257:
258: job_slot_t *s;
259:
1.7 ! snw 260: if (jobtab_get_sem () == FALSE) {
! 261: logprintf (FM_LOG_FATAL, "job_set_ecode: failed to get job table semaphore");
1.1 snw 262: }
263:
264: for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
265:
266: if (s->pid == target_pid) {
267: strncpy (s->last_ecode, ecode, 20);
268: jobtab_release_sem ();
269: return;
270: }
271:
272: }
273:
274: jobtab_release_sem ();
275:
276: }
277:
278: pid_t job_stop_requested (const pid_t target_pid)
279: {
280:
281: job_slot_t *s;
282:
283: for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
284: if (s->pid == target_pid) {
285: return s->stop_requested;
286: }
287: }
288:
289: return (pid_t) 0;
290:
291: }
292:
293: void job_request_all_stop(void)
294: {
295:
296: job_slot_t *s;
297:
298:
299: for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
300:
301: if ((s->flags & JFLG_DAEMON) != JFLG_DAEMON) {
302: job_request_stop (s->pid);
303: }
304:
305: }
306:
307:
308: }
309:
310: void job_signal_all(const int sig)
311: {
312:
313: job_slot_t *s;
314:
315: for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
316:
317: if ((s->flags & JFLG_DAEMON) != JFLG_DAEMON) {
318: kill (s->pid, sig);
319: }
320:
321: }
322:
323: }
324:
325:
326: int job_count(void)
327: {
328:
329: job_slot_t *s;
330: int ct = 0;
331:
332: for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
333:
334: if ((s->flags & JFLG_DEFUNCT) != JFLG_DEFUNCT) {
335: ct++;
336: }
337:
338: }
339:
340: return ct;
341:
342: }
343:
344: job_slot_t *job_set_status(const pid_t target_pid, const unsigned short status)
345: {
346:
347: job_slot_t *s;
348:
1.7 ! snw 349: if (jobtab_get_sem () == FALSE) {
! 350: logprintf (FM_LOG_FATAL, "job_set_status: failed to get job table semaphore");
1.1 snw 351: }
352:
353: for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
354:
355: if (s->pid == target_pid) {
356: s->status = status;
357: jobtab_release_sem ();
358: return s;
359: }
360:
361: }
362:
363: jobtab_release_sem ();
364:
365: return (job_slot_t *) NULL;
366:
367: }
368:
369: void job_gc_mark(void)
370: {
371:
372: job_slot_t *s;
1.7 ! snw 373: int jobstat;
1.1 snw 374:
375: if (jobtab_get_sem () == FALSE) {
1.7 ! snw 376: logprintf (FM_LOG_FATAL, "job_gc_mark: failed to get job table semaphore");
1.1 snw 377: }
378:
379: for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
380:
1.7 ! snw 381: if ((jobstat = kill (s->pid, 0)) != 0) {
! 382:
! 383: switch (jobstat) {
! 384:
! 385: case EPERM:
! 386: logprintf (FM_LOG_WARNING, "job_gc_mark: environment daemon lacks permissions to pid %ld", (long) s->pid);
! 387: break;
! 388:
! 389: case ESRCH:
! 390: logprintf (FM_LOG_INFO, "job_gc_mark: marking pid %ld DEFUNCT", (long) s->pid);
! 391: s->flags = JFLG_DEFUNCT;
! 392: break;
! 393:
! 394: }
! 395:
1.1 snw 396: }
397:
398: if ((s->flags & JFLG_NEW) == JFLG_NEW) {
399: if ((s->flags & JFLG_DAEMON) == JFLG_DAEMON) {
1.7 ! snw 400: logprintf (FM_LOG_INFO, "job_gc_mark: registering new daemon %ld", (long) s->pid);
1.1 snw 401: s->flags = JFLG_ALIVE | JFLG_DAEMON;
402: }
403: else {
404: if ((s->flags & JFLG_FMADM) == JFLG_FMADM) {
1.7 ! snw 405: logprintf (FM_LOG_INFO, "job_gc_mark: registering new fmadm process %ld", (long) s->pid);
1.1 snw 406: s->flags = JFLG_ALIVE | JFLG_FMADM;
407: }
408: else {
1.7 ! snw 409: logprintf (FM_LOG_INFO, "job_gc_mark: registering new interpreter process %ld", (long) s->pid);
1.1 snw 410: s->flags = JFLG_ALIVE;
411: }
412: }
413: }
414:
415: }
416:
417: jobtab_release_sem ();
418:
419: }
420:
421: void job_gc_sweep(void)
422: {
423:
424: job_slot_t *s;
425: char *k_buf = (char *) malloc (STRLEN * sizeof (char));
426: NULLPTRCHK(k_buf,"job_gc_sweep");
427:
428: if (jobtab_get_sem () == FALSE) {
1.7 ! snw 429: logprintf (FM_LOG_FATAL, "job_gc_sweep: failed to get job table semaphore");
1.1 snw 430: }
431:
432:
433: for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
434:
435: if ((s->flags & JFLG_DEFUNCT) == JFLG_DEFUNCT) {
436:
1.7 ! snw 437: logprintf (FM_LOG_INFO, "job_gc_sweep: sweeping DEFUNCT pid %ld", (long) s->pid);
1.1 snw 438:
439: snprintf (k_buf, STRLEN - 1, "^$JOB\202%d\201", s->pid);
440:
441: symtab_shm (kill_sym, k_buf, " \201");
442: merr_clear ();
443:
444: job_remove (s->pid);
445:
446: free (k_buf);
447:
448: jobtab_release_sem ();
449: return;
450:
451: }
452:
453: }
454:
455: free (k_buf);
456:
457: jobtab_release_sem ();
458:
459: }
460:
461: ipc_slot_t *job_send_ipc(const pid_t receiver_pid, const void *object)
462: {
463:
464: job_slot_t *j;
465: ipc_slot_t *s = (ipc_slot_t *) shm_alloc (sizeof (ipc_slot_t));
466: NULLPTRCHK(s,"job_send_ipc");
467:
1.7 ! snw 468: if (jobtab_get_sem () == FALSE) {
! 469: logprintf (FM_LOG_FATAL, "job_send_ipc: failed to get job table semaphore");
1.1 snw 470: }
471:
472:
473: for (j = shm_config->hdr->jobtab_head; j != NULL; j = j->next) {
474:
475: if (j->pid == receiver_pid) {
476:
477: s->flags = JIPCFLG_PENDING;
478: s->sender_pid = pid;
479: s->object = (void *) object;
480:
481: s->next = j->ipc_head;
482: j->ipc_head = s;
483:
484: jobtab_release_sem ();
485:
486: return s;
487:
488: }
489:
490: }
491:
492: shm_free (s);
493:
494: jobtab_release_sem ();
495:
496: return (ipc_slot_t *) NULL;
497:
498: }
499:
500: job_slot_t *job_get(const pid_t target_pid)
501: {
502:
503: job_slot_t *s;
504:
505: for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
506: if (s->pid == target_pid) return s;
507: }
508:
509: return (job_slot_t *) NULL;
510:
511: }
512:
513: void job_dump(void)
514: {
515: char time_buf[20];
516: char *flag_s = (char *) malloc (256 * sizeof (char));
517: char *stat_s = (char *) malloc (256 * sizeof (char));
518:
519: job_slot_t *s;
520:
521: flag_s[0] = '\0';
522: stat_s[0] = '\0';
523:
524: printf ("%-10s%-15s%-20s%-22s%s\r\n", "PID", "STATUS", "LAST ECODE", "STARTED", "FLAGS");
525: printf ("%-10s%-15s%-20s%-22s%s\r\n", "---", "------", "----------", "-------", "-----");
526:
527: for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
528:
529: strftime (time_buf, 20, "%Y-%m-%d %H:%M:%S", localtime (&(s->start_time)));
530:
531: flag_s[0] = '\0';
532: stat_s[0] = '\0';
533:
534: if ((s->flags & JFLG_ALIVE) == JFLG_ALIVE) strcat (flag_s, "ALIVE ");
535: if ((s->flags & JFLG_DEFUNCT) == JFLG_DEFUNCT) strcat (flag_s, "DEFUNCT ");
536: if ((s->flags & JFLG_REPLSENDER) == JFLG_REPLSENDER) strcat (flag_s, "REPLSENDER ");
537: if ((s->flags & JFLG_REPLRECEIVER) == JFLG_REPLRECEIVER) strcat (flag_s, "REPLRECEIVER ");
538: if ((s->flags & JFLG_FMADM) == JFLG_FMADM) strcat (flag_s, "FMADM ");
539: if ((s->flags & JFLG_NEW) == JFLG_NEW) strcat (flag_s, "NEW ");
540: if ((s->flags & JFLG_DAEMON) == JFLG_DAEMON) strcat (flag_s, "DAEMON ");
541:
542: if (s->status == JSTAT_IDLE) strcat (stat_s, "IDLE");
543: if (s->status == JSTAT_INTERPRETER) strcat (stat_s, "INTERPRETER");
544: if (s->status == JSTAT_HOUSEKEEPING) strcat (stat_s, "HOUSEKEEPING");
545: if (s->status == JSTAT_DIRECTMODE) strcat (stat_s, "DIRECTMODE");
546: if (s->status == JSTAT_ERROR) strcat (stat_s, "ERROR");
547: if (s->status == JSTAT_SHUTDOWN) strcat (stat_s, "SHUTDOWN");
548:
549: printf ("%-10d%-15s%-20s%-22s%s\r\n", s->pid, stat_s, s->last_ecode, time_buf, flag_s);
550:
551:
552: }
553:
554: free (stat_s);
555: free (flag_s);
556:
557: }
558:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>