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

1.1       snw         1: /*
                      2:  *                            *
                      3:  *                           * *
                      4:  *                          *   *
                      5:  *                     ***************
                      6:  *                      * *       * *
                      7:  *                       *  MUMPS  *
                      8:  *                      * *       * *
                      9:  *                     ***************
                     10:  *                          *   *
                     11:  *                           * *
                     12:  *                            *
                     13:  *
                     14:  *   jobtab.c
                     15:  *    job table implementation
                     16:  *
                     17:  *  
                     18:  *   Author: Serena Willis <jpw@coherent-logic.com>
                     19:  *    Copyright (C) 1998 MUG Deutschland
                     20:  *    Copyright (C) 2021, 2023 Coherent Logic Development LLC
                     21:  *
                     22:  *
                     23:  *   This file is part of FreeM.
                     24:  *
                     25:  *   FreeM is free software: you can redistribute it and/or modify
                     26:  *   it under the terms of the GNU Affero Public License as published by
                     27:  *   the Free Software Foundation, either version 3 of the License, or
                     28:  *   (at your option) any later version.
                     29:  *
                     30:  *   FreeM is distributed in the hope that it will be useful,
                     31:  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
                     32:  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     33:  *   GNU Affero Public License for more details.
                     34:  *
                     35:  *   You should have received a copy of the GNU Affero Public License
                     36:  *   along with FreeM.  If not, see <https://www.gnu.org/licenses/>.
                     37:  *
                     38:  **/
                     39: #include <stdlib.h>
                     40: #include <string.h>
                     41: #include <time.h>
                     42: #include <unistd.h>
                     43: 
                     44: #include "mpsdef.h"
                     45: #include "shmmgr.h"
                     46: #include "jobtab.h"
                     47: 
                     48: #if !defined(__OpenBSD__) && !defined(__APPLE__)
                     49: union semun {
                     50:     int              val;    /* Value for SETVAL */
                     51:     struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
                     52:     unsigned short  *array;  /* Array for GETALL, SETALL */
                     53:     struct seminfo  *__buf;  /* Buffer for IPC_INFO
                     54:                                 (Linux-specific) */
                     55: };
                     56: #endif
                     57: 
                     58: int semid_jobtab;
                     59: short have_jobtab_sem = FALSE;
                     60: 
                     61: void jobtab_init(void)
                     62: {
                     63:     union semun arg;
                     64:     key_t jt_sk;
                     65: 
                     66:     jt_sk = ftok (config_file, 2);
                     67:     if (first_process) {
                     68: 
                     69:         semid_jobtab = semget (jt_sk, 1, 0666 | IPC_CREAT);
                     70:         if (semid_jobtab == -1) {
                     71:             fprintf (stderr, "jobtab_init:  failed to create job table semaphore\r\n");
                     72:             exit (1);
                     73:         }
                     74:         else {
                     75:             fprintf (stderr, "jobtab_init:  job table semaphore created with semid %d\r\n", semid_jobtab);
                     76:         }
                     77: 
                     78:         arg.val = 1;
                     79:         if (semctl (semid_jobtab, 0, SETVAL, arg) == -1) {
                     80:             fprintf (stderr, "jobtab_init:  failed to initialize job table semaphore\r\n");
                     81:             exit (1);
                     82:         }
                     83:         else {
                     84:             fprintf (stderr, "jobtab_init:  job table semaphore initialized\r\n");
                     85:         }
                     86:         
                     87:     }
                     88:     else {
                     89: 
                     90:         semid_jobtab = semget (jt_sk, 1, 0);
                     91:         if (semid_jobtab == -1) {
                     92:             fprintf (stderr, "jobtab_init:  could not attach to job table semaphore\r\n");
                     93:             exit (1);
                     94:         }
                     95:         
                     96:     }
                     97:     
                     98:     return;
                     99: }
                    100: 
                    101: short jobtab_get_sem(void)
                    102: {
                    103:     int tries;
                    104:     struct sembuf s = {0, -1, IPC_NOWAIT};
                    105: 
                    106:     if (have_jobtab_sem) {
                    107: //        fprintf (stderr, "jobtab_get_sem:  this process already owns the job table semaphore\r\n");
                    108:         return TRUE;
                    109:     }
                    110:     
                    111:     for (tries = 0; tries < 5; tries++) {
                    112: 
                    113:         if (semop (semid_jobtab, &s, 1) != -1) {
                    114:             have_jobtab_sem = TRUE;           
                    115:             return TRUE;
                    116:         }
                    117: 
                    118:         /* fprintf (stderr, "jobtab_get_sem:  sleeping for retry [tries = %d]\r\n", tries); */
                    119: 
                    120:         sleep (1);
                    121: 
                    122:     }
                    123:     fprintf (stderr, "jobtab_get_sem:  fail\r\n");
                    124:     
                    125:     have_jobtab_sem = FALSE;
                    126:     return FALSE;
                    127: }
                    128: 
                    129: void jobtab_release_sem(void)
                    130: {
                    131:     struct sembuf s = {0, 1, 0};
                    132: 
                    133:     semop (semid_jobtab, &s, 1);
                    134: 
                    135:     have_jobtab_sem = FALSE;
                    136: }
                    137: 
                    138: 
                    139: job_slot_t *job_init(short is_fmadm)
                    140: {
                    141: 
                    142:     job_slot_t *s;
                    143:         
                    144:     if (jobtab_get_sem () == FALSE) {
                    145:         fprintf (stderr, "job_init:  failed to get job table semaphore\r\n");
                    146:         exit (1);
                    147:     }
                    148: 
                    149:     for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
                    150: 
                    151:         if (((s->flags & JFLG_DEFUNCT) == JFLG_DEFUNCT) || (s->pid == pid)) {
                    152:             goto skip_alloc;
                    153:         }
                    154:         
                    155:     }
                    156: 
                    157:     s = (job_slot_t *) shm_alloc (sizeof (job_slot_t));
                    158:     NULLPTRCHK(s,"job_init");
                    159: 
                    160:     
                    161: skip_alloc:    
                    162:     
                    163:     s->pid = pid;    
                    164:     s->ipc_head = (ipc_slot_t *) NULL;
                    165:     s->status = JSTAT_IDLE;
                    166:     s->start_time = time (NULL);
                    167:     s->stop_requested = 0;
                    168:     
                    169:     if (first_process) {
                    170:         s->flags = JFLG_DAEMON | JFLG_NEW;
                    171:     }
                    172:     else {
                    173:         if (is_fmadm == TRUE) {
                    174:             s->flags = JFLG_NEW | JFLG_FMADM;
                    175:         }
                    176:         else {
                    177:             s->flags = JFLG_NEW;
                    178:         }
                    179:     }
                    180:     
                    181:     s->next = shm_config->hdr->jobtab_head;
                    182:     shm_config->hdr->jobtab_head = s;
                    183: 
                    184:     jobtab_release_sem ();
                    185:     
                    186:     return s;
                    187:     
                    188: }
                    189: 
                    190: void job_remove(const pid_t pid)
                    191: {
                    192:     
                    193:     job_slot_t *t = shm_config->hdr->jobtab_head;
                    194:     job_slot_t *p = NULL;
                    195: 
                    196:     if (jobtab_get_sem() == FALSE) {
                    197:         fprintf (stderr, "job_remove:  failed to get job table semaphore\r\n");
                    198:         exit (1);
                    199:     }
                    200:     
                    201:     if ((t != (job_slot_t *) NULL) && (t->pid == pid)) {
                    202: 
                    203:         shm_config->hdr->jobtab_head = t->next;
                    204:         shm_free (t);
                    205: 
                    206:         jobtab_release_sem ();
                    207: 
                    208:         return;
                    209:         
                    210:     }
                    211: 
                    212:     while ((t != NULL) && (t->pid != pid)) {
                    213:         p = t;
                    214:         t = t->next;
                    215:     }
                    216: 
                    217:     if (t == NULL) {
                    218:         jobtab_release_sem ();
                    219:         return;
                    220:     }
                    221: 
                    222:     p->next = t->next;
                    223:     shm_free (t);
                    224: 
                    225:     jobtab_release_sem ();
                    226:     
                    227: }
                    228: 
                    229: void job_request_stop(const pid_t target_pid)
                    230: {
                    231: 
                    232:     job_slot_t *s;
                    233: 
                    234:     if (jobtab_get_sem() == FALSE) {
                    235:         fprintf (stderr, "job_request_stop:  failed to get job table semaphore\r\n");
                    236:         exit (1);
                    237:     }
                    238:     
                    239:     for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
                    240: 
                    241:         if (s->pid == target_pid) {
                    242:             s->stop_requested = pid;
                    243: 
                    244:             jobtab_release_sem ();
                    245:             job_set_status (target_pid, JSTAT_SHUTDOWN);
                    246:             
                    247:             return;
                    248:         }
                    249:         
                    250:     }
                    251: 
                    252:     jobtab_release_sem ();
                    253:     
                    254: }
                    255: 
                    256: void job_set_ecode(const pid_t target_pid, const char *ecode)
                    257: {
                    258: 
                    259:     job_slot_t *s;
                    260: 
                    261:     if (jobtab_get_sem() == FALSE) {
                    262:         fprintf (stderr, "job_set_ecode:  failed to get job table semaphore\r\n");
                    263:         exit (1);
                    264:     }
                    265:     
                    266:     for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
                    267: 
                    268:         if (s->pid == target_pid) {
                    269:             strncpy (s->last_ecode, ecode, 20);
                    270:             jobtab_release_sem ();
                    271:             return;
                    272:         }
                    273:         
                    274:     }
                    275: 
                    276:     jobtab_release_sem ();
                    277:     
                    278: }
                    279: 
                    280: pid_t job_stop_requested (const pid_t target_pid)
                    281: {
                    282: 
                    283:     job_slot_t *s;
                    284: 
                    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:         fprintf (stderr, "job_set_status:  failed to get job table semaphore\r\n");
                    354:         exit (1);
                    355:     }    
                    356:     
                    357:     for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
                    358: 
                    359:         if (s->pid == target_pid) {
                    360:             s->status = status;
                    361:             jobtab_release_sem ();
                    362:             return s;
                    363:         }
                    364:         
                    365:     }
                    366: 
                    367:     jobtab_release_sem ();
                    368: 
                    369:     return (job_slot_t *) NULL;
                    370: 
                    371: }
                    372: 
                    373: void job_gc_mark(void)
                    374: {
                    375: 
                    376:     job_slot_t *s;
                    377: 
                    378:     if (jobtab_get_sem () == FALSE) {
                    379:         fprintf (stderr, "job_gc_mark:  failed to get job table semaphore\r\n");
                    380:         exit (1);
                    381:     }
                    382: 
                    383:     for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
                    384:        
                    385:         if (kill (s->pid, 0) != 0) {
1.2     ! snw       386:             fprintf (stderr, "job_gc_mark:  marking pid %ld DEFUNCT\r\n", (long) s->pid);
1.1       snw       387:             s->flags = JFLG_DEFUNCT;
                    388:         }       
                    389: 
                    390:         if ((s->flags & JFLG_NEW) == JFLG_NEW) {
                    391:             if ((s->flags & JFLG_DAEMON) == JFLG_DAEMON) {
1.2     ! snw       392:                 fprintf (stderr, "job_gc_mark:  registering new daemon %ld\r\n", (long) s->pid);
1.1       snw       393:                 s->flags = JFLG_ALIVE | JFLG_DAEMON;
                    394:             }
                    395:             else {
                    396:                 if ((s->flags & JFLG_FMADM) == JFLG_FMADM) {
1.2     ! snw       397:                     fprintf (stderr, "job_gc_mark:  registering new fmadm process %ld\r\n", (long) s->pid);
1.1       snw       398:                     s->flags = JFLG_ALIVE | JFLG_FMADM;
                    399:                 }
                    400:                 else {
1.2     ! snw       401:                     fprintf (stderr, "job_gc_mark:  registering new interpreter process %ld\r\n", (long) s->pid);
1.1       snw       402:                     s->flags = JFLG_ALIVE;
                    403:                 }
                    404:             }
                    405:         }
                    406:         
                    407:     }
                    408: 
                    409:     jobtab_release_sem ();
                    410:     
                    411: }
                    412: 
                    413: void job_gc_sweep(void)
                    414: {
                    415: 
                    416:     job_slot_t *s;
                    417:     char *k_buf = (char *) malloc (STRLEN * sizeof (char));
                    418:     NULLPTRCHK(k_buf,"job_gc_sweep");
                    419: 
                    420:     if (jobtab_get_sem () == FALSE) {
                    421:         fprintf (stderr, "job_gc_sweep:  failed to get job table semaphore\r\n");
                    422:         exit (1);
                    423:     }
                    424: 
                    425:     
                    426:     for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
                    427: 
                    428:         if ((s->flags & JFLG_DEFUNCT) == JFLG_DEFUNCT) {
                    429: 
1.2     ! snw       430:             fprintf (stderr, "job_gc_sweep:  sweeping DEFUNCT pid %ld\r\n", (long) s->pid);
1.1       snw       431: 
                    432:             snprintf (k_buf, STRLEN - 1, "^$JOB\202%d\201", s->pid);
                    433: 
                    434:             symtab_shm (kill_sym, k_buf, " \201");
                    435:             merr_clear ();
                    436:             
                    437:             job_remove (s->pid);
                    438: 
                    439:             free (k_buf);
                    440: 
                    441:             jobtab_release_sem ();
                    442:             return;                     
                    443:             
                    444:         }
                    445:         
                    446:     }
                    447: 
                    448:     free (k_buf);
                    449: 
                    450:     jobtab_release_sem ();
                    451:     
                    452: }
                    453: 
                    454: ipc_slot_t *job_send_ipc(const pid_t receiver_pid, const void *object)
                    455: {
                    456: 
                    457:     job_slot_t *j;
                    458:     ipc_slot_t *s = (ipc_slot_t *) shm_alloc (sizeof (ipc_slot_t));
                    459:     NULLPTRCHK(s,"job_send_ipc");
                    460: 
                    461:     if (jobtab_get_sem() == FALSE) {
                    462:         fprintf (stderr, "job_send_ipc:  failed to get job table semaphore\r\n");
                    463:         exit (1);
                    464:     }
                    465: 
                    466:     
                    467:     for (j = shm_config->hdr->jobtab_head; j != NULL; j = j->next) {
                    468: 
                    469:         if (j->pid == receiver_pid) {
                    470:             
                    471:             s->flags = JIPCFLG_PENDING;
                    472:             s->sender_pid = pid;
                    473:             s->object = (void *) object;
                    474: 
                    475:             s->next = j->ipc_head;
                    476:             j->ipc_head = s;
                    477: 
                    478:             jobtab_release_sem ();
                    479:             
                    480:             return s;
                    481:             
                    482:         }
                    483: 
                    484:     }
                    485: 
                    486:     shm_free (s);
                    487: 
                    488:     jobtab_release_sem ();
                    489:     
                    490:     return (ipc_slot_t *) NULL;
                    491:     
                    492: }
                    493: 
                    494: job_slot_t *job_get(const pid_t target_pid)
                    495: {
                    496:     
                    497:     job_slot_t *s;
                    498: 
                    499:     for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
                    500:         if (s->pid == target_pid) return s;        
                    501:     }
                    502: 
                    503:     return (job_slot_t *) NULL;
                    504: 
                    505: }
                    506: 
                    507: void job_dump(void)
                    508: {
                    509:     char time_buf[20];
                    510:     char *flag_s = (char *) malloc (256 * sizeof (char));
                    511:     char *stat_s = (char *) malloc (256 * sizeof (char));    
                    512:     
                    513:     job_slot_t *s;
                    514: 
                    515:     flag_s[0] = '\0';
                    516:     stat_s[0] = '\0';
                    517:     
                    518:     printf ("%-10s%-15s%-20s%-22s%s\r\n", "PID", "STATUS", "LAST ECODE", "STARTED", "FLAGS");
                    519:     printf ("%-10s%-15s%-20s%-22s%s\r\n", "---", "------", "----------", "-------", "-----");
                    520:     
                    521:     for (s = shm_config->hdr->jobtab_head; s != NULL; s = s->next) {
                    522: 
                    523:         strftime (time_buf, 20, "%Y-%m-%d %H:%M:%S", localtime (&(s->start_time)));
                    524:         
                    525:         flag_s[0] = '\0';
                    526:         stat_s[0] = '\0';
                    527:         
                    528:         if ((s->flags & JFLG_ALIVE) == JFLG_ALIVE) strcat (flag_s, "ALIVE ");
                    529:         if ((s->flags & JFLG_DEFUNCT) == JFLG_DEFUNCT) strcat (flag_s, "DEFUNCT ");
                    530:         if ((s->flags & JFLG_REPLSENDER) == JFLG_REPLSENDER) strcat (flag_s, "REPLSENDER ");
                    531:         if ((s->flags & JFLG_REPLRECEIVER) == JFLG_REPLRECEIVER) strcat (flag_s, "REPLRECEIVER ");
                    532:         if ((s->flags & JFLG_FMADM) == JFLG_FMADM) strcat (flag_s, "FMADM ");
                    533:         if ((s->flags & JFLG_NEW) == JFLG_NEW) strcat (flag_s, "NEW ");
                    534:         if ((s->flags & JFLG_DAEMON) == JFLG_DAEMON) strcat (flag_s, "DAEMON ");
                    535: 
                    536:         if (s->status == JSTAT_IDLE) strcat (stat_s, "IDLE");
                    537:         if (s->status == JSTAT_INTERPRETER) strcat (stat_s, "INTERPRETER");
                    538:         if (s->status == JSTAT_HOUSEKEEPING) strcat (stat_s, "HOUSEKEEPING");
                    539:         if (s->status == JSTAT_DIRECTMODE) strcat (stat_s, "DIRECTMODE");
                    540:         if (s->status == JSTAT_ERROR) strcat (stat_s, "ERROR");
                    541:         if (s->status == JSTAT_SHUTDOWN) strcat (stat_s, "SHUTDOWN");
                    542: 
                    543:         printf ("%-10d%-15s%-20s%-22s%s\r\n", s->pid, stat_s, s->last_ecode, time_buf, flag_s);
                    544:        
                    545:         
                    546:     }
                    547: 
                    548:     free (stat_s);
                    549:     free (flag_s);
                    550:     
                    551: }
                    552: 

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