Annotation of freem/src/jobtab.c, revision 1.5

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

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