Diff for /freem/src/jobtab.c between versions 1.1.1.1 and 1.11

version 1.1.1.1, 2025/01/19 02:04:04 version 1.11, 2025/05/14 12:22:04
Line 1 Line 1
 /*  /*
  *                            *   *   $Id$
  *                           * *  
  *                          *   *  
  *                     ***************  
  *                      * *       * *  
  *                       *  MUMPS  *  
  *                      * *       * *  
  *                     ***************  
  *                          *   *  
  *                           * *  
  *                            *  
  *  
  *   jobtab.c  
  *    job table implementation   *    job table implementation
  *   *
  *     *  
  *   Author: Serena Willis <jpw@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.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 86  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 105  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 121  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 150  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 167  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 202  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 214  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 234  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 242  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 256  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 281  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 303  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 320  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 336  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 353  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 370  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 394  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 %d DEFUNCT\r\n", 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 %d\r\n", 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 %d\r\n", 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 %d\r\n", 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 450  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", 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 489  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 526  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 548  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)));
                   

Removed from v.1.1.1.1  
changed lines
  Added in v.1.11


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>