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