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