File:  [Coherent Logic Development] / freem / src / jobtab.c
Revision 1.7: download - view: text, annotated - select for diffs
Thu Apr 17 00:34:04 2025 UTC (5 months, 4 weeks ago) by snw
Branches: MAIN
CVS tags: HEAD
More logging improvements

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

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