version 1.3, 2025/03/09 15:20:18
|
version 1.12, 2025/05/14 15:28:55
|
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.12 2025/05/14 15:28:55 snw |
|
* Get basic job table and lock table functionality working with new shared memory architecture |
|
* |
|
* Revision 1.11 2025/05/14 12:22:04 snw |
|
* Further work on shared memory |
|
* |
|
* 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 89 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 108 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 103 short jobtab_get_sem(void)
|
Line 124 short jobtab_get_sem(void)
|
int tries; |
int tries; |
struct sembuf s = {0, -1, IPC_NOWAIT}; |
struct sembuf s = {0, -1, IPC_NOWAIT}; |
|
|
|
logprintf (FM_LOG_DEBUG, "jobtab_get_sem: attempting to acquire job table semaphore"); |
|
|
if (have_jobtab_sem) { |
if (have_jobtab_sem) { |
// fprintf (stderr, "jobtab_get_sem: this process already owns the job table semaphore\r\n"); |
logprintf (FM_LOG_DEBUG, "jobtab_get_sem: acquired semaphore by virtue of already owning it"); |
return TRUE; |
return TRUE; |
} |
} |
|
|
for (tries = 0; tries < 5; tries++) { |
for (tries = 0; tries < 5; tries++) { |
|
|
if (semop (semid_jobtab, &s, 1) != -1) { |
if (semop (semid_jobtab, &s, 1) != -1) { |
|
logprintf (FM_LOG_DEBUG, "jobtab_get_sem: acquired semaphore by virtue of calling semop on it"); |
have_jobtab_sem = TRUE; |
have_jobtab_sem = TRUE; |
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; errno = %d; error = %s]", tries, errno, strerror (errno)); |
|
|
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 130 void jobtab_release_sem(void)
|
Line 153 void jobtab_release_sem(void)
|
{ |
{ |
struct sembuf s = {0, 1, 0}; |
struct sembuf s = {0, 1, 0}; |
|
|
semop (semid_jobtab, &s, 1); |
logprintf (FM_LOG_DEBUG, "jobtab_release_sem: trying to release job table semaphore"); |
|
if (semop (semid_jobtab, &s, 1) != -1) { |
have_jobtab_sem = FALSE; |
logprintf (FM_LOG_DEBUG, "jobtab_release_sem: released job table semaphore by means of semop"); |
|
have_jobtab_sem = FALSE; |
|
} |
|
else { |
|
logprintf (FM_LOG_FATAL, "jobtab_release_sem: failed to release job table semaphore (error code %d [%s])", errno, strerror (errno)); |
|
} |
} |
} |
|
|
|
|
Line 142 job_slot_t *job_init(short is_fmadm)
|
Line 170 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 205 skip_alloc:
|
} |
} |
} |
} |
|
|
s->next = shm_config->hdr->jobtab_head; |
s->next = SBM(SOA(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 217 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(SOA(t->next)); |
shm_free (t); |
shm_free (t); |
|
|
jobtab_release_sem (); |
jobtab_release_sem (); |
Line 211 void job_remove(const pid_t pid)
|
Line 237 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 = SOA(t->next); |
} |
} |
|
|
if (t == NULL) { |
if (t == NULL) { |
Line 219 void job_remove(const pid_t pid)
|
Line 245 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 259 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 284 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 = SOA(shm_config->hdr->jobtab_head); s != NULL; s = SOA(s->next)) { |
|
|
if (s->pid == target_pid) { |
if (s->pid == target_pid) { |
strncpy (s->last_ecode, ecode, 20); |
strncpy (s->last_ecode, ecode, 20); |
Line 281 pid_t job_stop_requested (const pid_t ta
|
Line 306 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 = SOA(shm_config->hdr->jobtab_head); s != NULL; s = SOA(s->next)) { |
if (s->pid == target_pid) { |
if (s->pid == target_pid) { |
return s->stop_requested; |
return s->stop_requested; |
} |
} |
Line 299 void job_request_all_stop(void)
|
Line 323 void job_request_all_stop(void)
|
job_slot_t *s; |
job_slot_t *s; |
|
|
|
|
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_DAEMON) != JFLG_DAEMON) { |
if ((s->flags & JFLG_DAEMON) != JFLG_DAEMON) { |
job_request_stop (s->pid); |
job_request_stop (s->pid); |
Line 315 void job_signal_all(const int sig)
|
Line 339 void job_signal_all(const int sig)
|
|
|
job_slot_t *s; |
job_slot_t *s; |
|
|
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_DAEMON) != JFLG_DAEMON) { |
if ((s->flags & JFLG_DAEMON) != JFLG_DAEMON) { |
kill (s->pid, sig); |
kill (s->pid, sig); |
Line 332 int job_count(void)
|
Line 356 int job_count(void)
|
job_slot_t *s; |
job_slot_t *s; |
int ct = 0; |
int ct = 0; |
|
|
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) { |
if ((s->flags & JFLG_DEFUNCT) != JFLG_DEFUNCT) { |
ct++; |
ct++; |
Line 349 job_slot_t *job_set_status(const pid_t t
|
Line 373 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 = SOA(shm_config->hdr->jobtab_head); s != NULL; s = SOA(s->next)) { |
|
|
if (s->pid == target_pid) { |
if (s->pid == target_pid) { |
s->status = status; |
s->status = status; |
Line 374 void job_gc_mark(void)
|
Line 397 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 = SOA(shm_config->hdr->jobtab_head); s != NULL; s = SOA(s->next)) { |
|
logprintf (FM_LOG_WARNING, "job_gc_mark looking at pid %ld", s->pid); |
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 453 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); |
|
} |
} |
|
|
|
|
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) { |
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 492 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); |
|
} |
} |
|
|
|
|
for (j = shm_config->hdr->jobtab_head; j != NULL; j = j->next) { |
for (j = SOA(shm_config->hdr->jobtab_head); j != NULL; j = SOA(j->next)) { |
|
|
if (j->pid == receiver_pid) { |
if (j->pid == receiver_pid) { |
|
|
Line 496 job_slot_t *job_get(const pid_t target_p
|
Line 529 job_slot_t *job_get(const pid_t target_p
|
|
|
job_slot_t *s; |
job_slot_t *s; |
|
|
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) return s; |
if (s->pid == target_pid) return s; |
} |
} |
|
|
Line 518 void job_dump(void)
|
Line 551 void job_dump(void)
|
printf ("%-10s%-15s%-20s%-22s%s\r\n", "PID", "STATUS", "LAST ECODE", "STARTED", "FLAGS"); |
printf ("%-10s%-15s%-20s%-22s%s\r\n", "PID", "STATUS", "LAST ECODE", "STARTED", "FLAGS"); |
printf ("%-10s%-15s%-20s%-22s%s\r\n", "---", "------", "----------", "-------", "-----"); |
printf ("%-10s%-15s%-20s%-22s%s\r\n", "---", "------", "----------", "-------", "-----"); |
|
|
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)) { |
|
|
strftime (time_buf, 20, "%Y-%m-%d %H:%M:%S", localtime (&(s->start_time))); |
strftime (time_buf, 20, "%Y-%m-%d %H:%M:%S", localtime (&(s->start_time))); |
|
|