|
|
| version 1.3, 2025/03/09 15:20:18 | version 1.10, 2025/05/12 18:18:00 |
|---|---|
| Line 1 | Line 1 |
| /* | /* |
| * * | * $Id$ |
| * * * | |
| * * * | |
| * *************** | |
| * * * * * | |
| * * MUMPS * | |
| * * * * * | |
| * *************** | |
| * * * | |
| * * * | |
| * * | |
| * | |
| * jobtab.c | |
| * job table implementation | * job table implementation |
| * | * |
| * | * |
| * Author: Serena Willis <snw@coherent-logic.com> | * Author: Serena Willis <snw@coherent-logic.com> |
| * Copyright (C) 1998 MUG Deutschland | * Copyright (C) 1998 MUG Deutschland |
| * Copyright (C) 2021, 2023 Coherent Logic Development LLC | * Copyright (C) 2021, 2023, 2025 Coherent Logic Development LLC |
| * | * |
| * | * |
| * This file is part of FreeM. | * This file is part of FreeM. |
| Line 35 | Line 23 |
| * You should have received a copy of the GNU Affero Public License | * You should have received a copy of the GNU Affero Public License |
| * along with FreeM. If not, see <https://www.gnu.org/licenses/>. | * along with FreeM. If not, see <https://www.gnu.org/licenses/>. |
| * | * |
| * $Log$ | |
| * Revision 1.10 2025/05/12 18:18:00 snw | |
| * Further work on shared memory | |
| * | |
| * Revision 1.9 2025/05/01 21:02:31 snw | |
| * Documentation updates | |
| * | |
| * Revision 1.8 2025/04/30 20:03:09 snw | |
| * Work on entryref parser | |
| * | |
| * Revision 1.7 2025/04/17 00:34:04 snw | |
| * More logging improvements | |
| * | |
| * Revision 1.6 2025/04/10 01:24:38 snw | |
| * Remove C++ style comments | |
| * | |
| * Revision 1.5 2025/03/24 02:57:49 snw | |
| * Shared memory compatibility fixes for OS/2 | |
| * | |
| * Revision 1.4 2025/03/09 19:14:25 snw | |
| * First phase of REUSE compliance and header reformat | |
| * | |
| * | |
| * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC | |
| * SPDX-License-Identifier: AGPL-3.0-or-later | |
| **/ | **/ |
| #include <stdlib.h> | #include <stdlib.h> |
| #include <string.h> | #include <string.h> |
| #include <time.h> | #include <time.h> |
| #include <unistd.h> | #include <unistd.h> |
| #include <errno.h> | |
| #include "mpsdef.h" | #include "mpsdef.h" |
| #include "shmmgr.h" | #include "shmmgr.h" |
| #include "jobtab.h" | #include "jobtab.h" |
| #include "log.h" | |
| #if !defined(__OpenBSD__) && !defined(__APPLE__) | #if !defined(__OpenBSD__) && !defined(__APPLE__) && !defined(__OS2__) |
| union semun { | union semun { |
| int val; /* Value for SETVAL */ | int val; /* Value for SETVAL */ |
| struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ | struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ |
| Line 68 void jobtab_init(void) | Line 83 void jobtab_init(void) |
| semid_jobtab = semget (jt_sk, 1, 0666 | IPC_CREAT); | semid_jobtab = semget (jt_sk, 1, 0666 | IPC_CREAT); |
| if (semid_jobtab == -1) { | if (semid_jobtab == -1) { |
| fprintf (stderr, "jobtab_init: failed to create job table semaphore\r\n"); | logprintf (FM_LOG_FATAL, "jobtab_init: failed to create job table semaphore (error code %d [%s])", errno, strerror (errno)); |
| exit (1); | |
| } | } |
| else { | else { |
| fprintf (stderr, "jobtab_init: job table semaphore created with semid %d\r\n", semid_jobtab); | logprintf (FM_LOG_INFO, "jobtab_init: job table semaphore created with semid %d", semid_jobtab); |
| } | } |
| arg.val = 1; | arg.val = 1; |
| if (semctl (semid_jobtab, 0, SETVAL, arg) == -1) { | if (semctl (semid_jobtab, 0, SETVAL, arg) == -1) { |
| fprintf (stderr, "jobtab_init: failed to initialize job table semaphore\r\n"); | logprintf (FM_LOG_FATAL, "jobtab_init: failed to initialize job table semaphore (error code %d [%s])", errno, strerror (errno)); |
| exit (1); | |
| } | } |
| else { | else { |
| fprintf (stderr, "jobtab_init: job table semaphore initialized\r\n"); | logprintf (FM_LOG_INFO, "jobtab_init: job table semaphore initialized"); |
| } | } |
| } | } |
| Line 89 void jobtab_init(void) | Line 102 void jobtab_init(void) |
| semid_jobtab = semget (jt_sk, 1, 0); | semid_jobtab = semget (jt_sk, 1, 0); |
| if (semid_jobtab == -1) { | if (semid_jobtab == -1) { |
| fprintf (stderr, "jobtab_init: could not attach to job table semaphore\r\n"); | logprintf (FM_LOG_FATAL, "jobtab_init: could not attach to job table semaphore (error code %d [%s])", errno, strerror (errno)); |
| exit (1); | } |
| else { | |
| logprintf (FM_LOG_INFO, "jobtab_init: attached to job table semaphore (semid %d)", semid_jobtab); | |
| } | } |
| } | } |
| Line 104 short jobtab_get_sem(void) | Line 119 short jobtab_get_sem(void) |
| struct sembuf s = {0, -1, IPC_NOWAIT}; | struct sembuf s = {0, -1, IPC_NOWAIT}; |
| if (have_jobtab_sem) { | if (have_jobtab_sem) { |
| // fprintf (stderr, "jobtab_get_sem: this process already owns the job table semaphore\r\n"); | |
| return TRUE; | return TRUE; |
| } | } |
| Line 115 short jobtab_get_sem(void) | Line 129 short jobtab_get_sem(void) |
| return TRUE; | return TRUE; |
| } | } |
| /* fprintf (stderr, "jobtab_get_sem: sleeping for retry [tries = %d]\r\n", tries); */ | logprintf (FM_LOG_INFO, "jobtab_get_sem: sleeping for retry [tries = %d]", tries); |
| sleep (1); | sleep (1); |
| } | } |
| fprintf (stderr, "jobtab_get_sem: fail\r\n"); | logprintf (FM_LOG_ERROR, "jobtab_get_sem: failed to acquire job table semaphore"); |
| have_jobtab_sem = FALSE; | have_jobtab_sem = FALSE; |
| return FALSE; | return FALSE; |
| Line 142 job_slot_t *job_init(short is_fmadm) | Line 155 job_slot_t *job_init(short is_fmadm) |
| job_slot_t *s; | job_slot_t *s; |
| if (jobtab_get_sem () == FALSE) { | if (jobtab_get_sem () == FALSE) { |
| fprintf (stderr, "job_init: failed to get job table semaphore\r\n"); | logprintf (FM_LOG_FATAL, "job_init: failed to get job table semaphore"); |
| exit (1); | |
| } | } |
| for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) { | for (s = SOA(shm_config->hdr->jobtab_head); s != NULL; s = SOA(s->next)) { |
| if (((s->flags & JFLG_DEFUNCT) == JFLG_DEFUNCT) || (s->pid == pid)) { | if (((s->flags & JFLG_DEFUNCT) == JFLG_DEFUNCT) || (s->pid == pid)) { |
| goto skip_alloc; | goto skip_alloc; |
| Line 178 skip_alloc: | Line 190 skip_alloc: |
| } | } |
| } | } |
| s->next = shm_config->hdr->jobtab_head; | s->next = SBM(shm_config->hdr->jobtab_head); |
| shm_config->hdr->jobtab_head = s; | shm_config->hdr->jobtab_head = SBM(s); |
| jobtab_release_sem (); | jobtab_release_sem (); |
| Line 190 skip_alloc: | Line 202 skip_alloc: |
| void job_remove(const pid_t pid) | void job_remove(const pid_t pid) |
| { | { |
| job_slot_t *t = shm_config->hdr->jobtab_head; | job_slot_t *t = SOM(shm_config->hdr->jobtab_head); |
| job_slot_t *p = NULL; | job_slot_t *p = NULL; |
| if (jobtab_get_sem() == FALSE) { | if (jobtab_get_sem () == FALSE) { |
| fprintf (stderr, "job_remove: failed to get job table semaphore\r\n"); | logprintf (FM_LOG_FATAL, "job_remove: failed to get job table semaphore"); |
| exit (1); | |
| } | } |
| if ((t != (job_slot_t *) NULL) && (t->pid == pid)) { | if ((t != (job_slot_t *) NULL) && (t->pid == pid)) { |
| shm_config->hdr->jobtab_head = t->next; | shm_config->hdr->jobtab_head = SBM(t->next); |
| shm_free (t); | shm_free (t); |
| jobtab_release_sem (); | jobtab_release_sem (); |
| Line 211 void job_remove(const pid_t pid) | Line 222 void job_remove(const pid_t pid) |
| while ((t != NULL) && (t->pid != pid)) { | while ((t != NULL) && (t->pid != pid)) { |
| p = t; | p = t; |
| t = t->next; | t = SBA(t->next); |
| } | } |
| if (t == NULL) { | if (t == NULL) { |
| Line 219 void job_remove(const pid_t pid) | Line 230 void job_remove(const pid_t pid) |
| return; | return; |
| } | } |
| p->next = t->next; | p->next = SBA(t->next); |
| shm_free (t); | shm_free (t); |
| jobtab_release_sem (); | jobtab_release_sem (); |
| locktab_unlock_all_by_pid (pid); | |
| } | } |
| void job_request_stop(const pid_t target_pid) | void job_request_stop(const pid_t target_pid) |
| Line 232 void job_request_stop(const pid_t target | Line 244 void job_request_stop(const pid_t target |
| job_slot_t *s; | job_slot_t *s; |
| if (jobtab_get_sem() == FALSE) { | if (jobtab_get_sem() == FALSE) { |
| fprintf (stderr, "job_request_stop: failed to get job table semaphore\r\n"); | logprintf (FM_LOG_FATAL, "job_request_stop: failed to get job table semaphore"); |
| exit (1); | |
| } | } |
| for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) { | for (s = SOA(shm_config->hdr->jobtab_head); s != NULL; s = SOA(s->next)) { |
| if (s->pid == target_pid) { | if (s->pid == target_pid) { |
| s->stop_requested = pid; | s->stop_requested = pid; |
| Line 258 void job_set_ecode(const pid_t target_pi | Line 269 void job_set_ecode(const pid_t target_pi |
| job_slot_t *s; | job_slot_t *s; |
| if (jobtab_get_sem() == FALSE) { | if (jobtab_get_sem () == FALSE) { |
| fprintf (stderr, "job_set_ecode: failed to get job table semaphore\r\n"); | logprintf (FM_LOG_FATAL, "job_set_ecode: failed to get job table semaphore"); |
| exit (1); | |
| } | } |
| for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) { | for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) { |
| Line 281 pid_t job_stop_requested (const pid_t ta | Line 291 pid_t job_stop_requested (const pid_t ta |
| { | { |
| job_slot_t *s; | job_slot_t *s; |
| for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) { | for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) { |
| if (s->pid == target_pid) { | if (s->pid == target_pid) { |
| Line 349 job_slot_t *job_set_status(const pid_t t | Line 358 job_slot_t *job_set_status(const pid_t t |
| job_slot_t *s; | job_slot_t *s; |
| if (jobtab_get_sem() == FALSE) { | if (jobtab_get_sem () == FALSE) { |
| fprintf (stderr, "job_set_status: failed to get job table semaphore\r\n"); | logprintf (FM_LOG_FATAL, "job_set_status: failed to get job table semaphore"); |
| exit (1); | |
| } | } |
| for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) { | for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) { |
| Line 374 void job_gc_mark(void) | Line 382 void job_gc_mark(void) |
| { | { |
| job_slot_t *s; | job_slot_t *s; |
| int jobstat; | |
| if (jobtab_get_sem () == FALSE) { | if (jobtab_get_sem () == FALSE) { |
| fprintf (stderr, "job_gc_mark: failed to get job table semaphore\r\n"); | logprintf (FM_LOG_FATAL, "job_gc_mark: failed to get job table semaphore"); |
| exit (1); | |
| } | } |
| for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) { | for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) { |
| if (kill (s->pid, 0) != 0) { | if ((jobstat = kill (s->pid, 0)) != 0) { |
| fprintf (stderr, "job_gc_mark: marking pid %ld DEFUNCT\r\n", (long) s->pid); | |
| s->flags = JFLG_DEFUNCT; | switch (jobstat) { |
| case EPERM: | |
| logprintf (FM_LOG_WARNING, "job_gc_mark: environment daemon lacks permissions to pid %ld", (long) s->pid); | |
| break; | |
| case ESRCH: | |
| logprintf (FM_LOG_INFO, "job_gc_mark: marking pid %ld DEFUNCT", (long) s->pid); | |
| s->flags = JFLG_DEFUNCT; | |
| break; | |
| } | |
| } | } |
| if ((s->flags & JFLG_NEW) == JFLG_NEW) { | if ((s->flags & JFLG_NEW) == JFLG_NEW) { |
| if ((s->flags & JFLG_DAEMON) == JFLG_DAEMON) { | if ((s->flags & JFLG_DAEMON) == JFLG_DAEMON) { |
| fprintf (stderr, "job_gc_mark: registering new daemon %ld\r\n", (long) s->pid); | logprintf (FM_LOG_INFO, "job_gc_mark: registering new daemon %ld", (long) s->pid); |
| s->flags = JFLG_ALIVE | JFLG_DAEMON; | s->flags = JFLG_ALIVE | JFLG_DAEMON; |
| } | } |
| else { | else { |
| if ((s->flags & JFLG_FMADM) == JFLG_FMADM) { | if ((s->flags & JFLG_FMADM) == JFLG_FMADM) { |
| fprintf (stderr, "job_gc_mark: registering new fmadm process %ld\r\n", (long) s->pid); | logprintf (FM_LOG_INFO, "job_gc_mark: registering new fmadm process %ld", (long) s->pid); |
| s->flags = JFLG_ALIVE | JFLG_FMADM; | s->flags = JFLG_ALIVE | JFLG_FMADM; |
| } | } |
| else { | else { |
| fprintf (stderr, "job_gc_mark: registering new interpreter process %ld\r\n", (long) s->pid); | logprintf (FM_LOG_INFO, "job_gc_mark: registering new interpreter process %ld", (long) s->pid); |
| s->flags = JFLG_ALIVE; | s->flags = JFLG_ALIVE; |
| } | } |
| } | } |
| Line 418 void job_gc_sweep(void) | Line 438 void job_gc_sweep(void) |
| NULLPTRCHK(k_buf,"job_gc_sweep"); | NULLPTRCHK(k_buf,"job_gc_sweep"); |
| if (jobtab_get_sem () == FALSE) { | if (jobtab_get_sem () == FALSE) { |
| fprintf (stderr, "job_gc_sweep: failed to get job table semaphore\r\n"); | logprintf (FM_LOG_FATAL, "job_gc_sweep: failed to get job table semaphore"); |
| exit (1); | |
| } | } |
| Line 427 void job_gc_sweep(void) | Line 446 void job_gc_sweep(void) |
| if ((s->flags & JFLG_DEFUNCT) == JFLG_DEFUNCT) { | if ((s->flags & JFLG_DEFUNCT) == JFLG_DEFUNCT) { |
| fprintf (stderr, "job_gc_sweep: sweeping DEFUNCT pid %ld\r\n", (long) s->pid); | logprintf (FM_LOG_INFO, "job_gc_sweep: sweeping DEFUNCT pid %ld", (long) s->pid); |
| snprintf (k_buf, STRLEN - 1, "^$JOB\202%d\201", s->pid); | snprintf (k_buf, STRLEN - 1, "^$JOB\202%d\201", s->pid); |
| Line 458 ipc_slot_t *job_send_ipc(const pid_t rec | Line 477 ipc_slot_t *job_send_ipc(const pid_t rec |
| ipc_slot_t *s = (ipc_slot_t *) shm_alloc (sizeof (ipc_slot_t)); | ipc_slot_t *s = (ipc_slot_t *) shm_alloc (sizeof (ipc_slot_t)); |
| NULLPTRCHK(s,"job_send_ipc"); | NULLPTRCHK(s,"job_send_ipc"); |
| if (jobtab_get_sem() == FALSE) { | if (jobtab_get_sem () == FALSE) { |
| fprintf (stderr, "job_send_ipc: failed to get job table semaphore\r\n"); | logprintf (FM_LOG_FATAL, "job_send_ipc: failed to get job table semaphore"); |
| exit (1); | |
| } | } |