Annotation of freem/src/locktab.c, revision 1.7

1.1       snw         1: /*
1.7     ! snw         2:  *   $Id: locktab.c,v 1.6 2025/04/13 04:22:43 snw Exp $
1.1       snw         3:  *    lock 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, 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: locktab.c,v $
1.7     ! snw        27:  *   Revision 1.6  2025/04/13 04:22:43  snw
        !            28:  *   Fix snprintf calls
        !            29:  *
1.6       snw        30:  *   Revision 1.5  2025/03/24 02:57:25  snw
                     31:  *   Shared memory compatibility fixes for OS/2
                     32:  *
1.5       snw        33:  *   Revision 1.4  2025/03/09 19:14:25  snw
                     34:  *   First phase of REUSE compliance and header reformat
                     35:  *
1.4       snw        36:  *
                     37:  * SPDX-FileCopyrightText:  (C) 2025 Coherent Logic Development LLC
                     38:  * SPDX-License-Identifier: AGPL-3.0-or-later
1.1       snw        39:  **/
                     40: 
                     41: #include <stdio.h>
                     42: #include <stdlib.h>
                     43: #include <unistd.h>
                     44: #include <time.h>
                     45: #include <string.h>
                     46: 
                     47: #include "mpsdef.h"
                     48: #include "locktab.h"
                     49: #include "shmmgr.h"
                     50: #include "mref.h"
                     51: #include "transact.h"
1.7     ! snw        52: #include "log.h"
1.1       snw        53: 
1.5       snw        54: #if !defined(__OpenBSD__) && !defined(__APPLE__) && !defined(__OS2__)
1.1       snw        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_locktab;
                     65: 
                     66: int locktab_list_count(char *key);
                     67: 
                     68: void locktab_init(void)
                     69: {
                     70:     union semun arg;
                     71:     key_t lt_sk;
                     72: 
                     73:     lt_sk = ftok (config_file, 3);
                     74:     
                     75:     if (first_process) {
                     76: 
                     77:         semid_locktab = semget (lt_sk, 1, 0666 | IPC_CREAT);
                     78:         if (semid_locktab == -1) {
                     79:             fprintf (stderr, "locktab_init:  failed to create lock table semaphore\r\n");
                     80:             exit (1);
                     81:         }
                     82: 
                     83:         arg.val = 1;
                     84:         if (semctl (semid_locktab, 0, SETVAL, arg) == -1) {
                     85:             fprintf (stderr, "locktab_init:  failed to initialize lock table semaphore\r\n");
                     86:             exit (1);
                     87:         }
                     88:         
                     89:     }
                     90:     else {
                     91: 
                     92:         semid_locktab = semget (lt_sk, 1, 0);
                     93:         if (semid_locktab == -1) {
                     94:             fprintf (stderr, "locktab_init:  could not attach to lock table semaphore\r\n");
                     95:             exit (1);
                     96:         }
                     97:         
                     98:     }
                     99:     
                    100:     return;
                    101:     
                    102: }
                    103: 
                    104: short locktab_get_sem(void)
                    105: {
                    106:     int tries;
                    107:     struct sembuf s = {0, -1, 0};
                    108: 
                    109:     for (tries = 0; tries < 5; tries++) {
                    110: 
                    111:         if (semop (semid_locktab, &s, 1) != -1) {
                    112:             return TRUE;
                    113:         }
1.7     ! snw       114:         printf ("jibjaw\r\n");
1.1       snw       115:         sleep (1);
                    116: 
                    117:     }
                    118:     
                    119:     return FALSE;
                    120: }
                    121: 
                    122: void locktab_release_sem(void)
                    123: {
                    124:     struct sembuf s = {0, 1, 0};
                    125: 
                    126:     semop (semid_locktab, &s, 1);
                    127: 
                    128: }
                    129: 
                    130: void lock(char *lockarg, long time_out, char type)
                    131: {
                    132:     char *key = &(lockarg[1]);
                    133:     char a = lockarg[0];
                    134:     
                    135:     if (shm_config == NULL) {
                    136:         fprintf (stderr, "lock:  global LOCK operation attemped before shared memory available.\r\n");
                    137:         return;
                    138:     }
                    139: 
                    140:     switch (a) {
                    141: 
                    142:         case '+':
                    143:             locktab_increment (key, time_out, FALSE);
                    144:             break;
                    145:             
                    146:         case '-':
                    147:             locktab_decrement (key, time_out);
                    148:             break;
                    149:             
                    150:         case SP:
                    151:             locktab_unlock_all ();
                    152:             locktab_increment (key, time_out, TRUE);
                    153:             break;
                    154: 
                    155:         default:
                    156:             break;
                    157:             
                    158:     }
                    159: 
                    160:     return;
                    161:     
                    162: }
                    163: 
                    164: void locktab_increment(char *key, long lck_timeout, short old_lock)
                    165: {
                    166:     short lck_action;
                    167:     char chk_ns[256];
                    168:     int nref_ct = locktab_list_count (key);
                    169: 
                    170:     if (old_lock) {
                    171:         lck_action = lock_old;
                    172:     }
                    173:     else {
                    174:         lck_action = lock_inc;
                    175:     }
                    176: 
                    177:     strncpy (chk_ns, nsname, 256);
                    178:     
                    179:     switch (lck_timeout) {
                    180:             
                    181:         case -1: /* blocking lock (no timeout) */
                    182: 
                    183:             if (nref_ct > 1) {
                    184:                 /* this is a lock list */
                    185:                 char *nref;
                    186:                 char tmps[255];
                    187: 
                    188:                 int i;        
                    189:                 int successes = 0;
                    190:                 int attempts = 0;
                    191:                 int list_pos = 0;
                    192:                 
                    193:                 char *attempt_status = (char *) malloc (nref_ct * sizeof (char));
                    194:                 NULLPTRCHK(attempt_status,"locktab_increment");
                    195: 
                    196:                 for (i = 0; i < nref_ct; i++) attempt_status[i] = (char) FALSE;
                    197:                 
                    198:                 stcpy (tmps, key);
                    199:                 stcnv_m2c (tmps);                               
                    200:                 
                    201:                 nref = strtok (tmps, "\001\201");
                    202: 
                    203:                 do {
                    204:                     
                    205:                     list_pos = 0;                    
                    206:                     attempts = 0;
                    207:                     successes = 0;
                    208:                     
                    209:                     for (;;) {                    
                    210: 
                    211:                         attempts++;
                    212:                        
                    213:                         if (attempt_status[list_pos] == FALSE) {
                    214:                             
                    215:                             if (locktab_insert (nref) != NULL) {
                    216:                                 successes++;
                    217:                                 attempt_status[list_pos] = TRUE;
                    218:                             }
                    219:                             else {
                    220:                                 locktab_decrement (nref, -1L);
                    221:                                 attempt_status[list_pos] = FALSE;
                    222:                             }
                    223: 
                    224:                         }
                    225:                         
                    226:                         nref = strtok (NULL, "\001\201");                    
                    227:                         if (nref == NULL) break;
                    228: 
                    229:                         list_pos++;
                    230:                         
                    231:                     }                        
                    232: 
                    233:                 } while (successes < nref_ct);
                    234: 
                    235:                 free (attempt_status);
                    236:                 if (tp_level > 0) tp_add_op (TRUE, lck_action, key, chk_ns);
                    237:                 return;
                    238:                 
                    239:             }
                    240:             else {
1.7     ! snw       241:                 int sigint_ct = 0;
        !           242:                 
1.1       snw       243:                 for (;;) {
                    244:                     
                    245:                     if (locktab_insert (key) != NULL) {
                    246:                         if (tp_level > 0) tp_add_op (TRUE, lck_action, key, chk_ns);
                    247:                         return;
                    248:                     }
                    249:                     else {
1.7     ! snw       250:                         if (merr () == INRPT) {
        !           251:                             sigint_ct++;
        !           252: 
        !           253:                             if (sigint_ct == 1) {
        !           254:                                 printf ("\r\nlocktab_insert:  got Ctrl-C in blocking LOCK; Ctrl-C again to force the process to halt\r\n");
        !           255:                                 merr_clear ();
        !           256:                             }
        !           257:                             else {
        !           258:                                 printf ("\r\n");
        !           259:                                 logprintf (FM_LOG_FATAL, "locktab_insert:  blocking LOCK was interrupted; forcing halt");
        !           260:                             }
        !           261:                         }
1.1       snw       262:                         sleep (1);
                    263:                     }
                    264:                 
                    265:                 }
                    266:             }
                    267: 
                    268:             
                    269:         case 0: /* lock that returns immediately */
                    270: 
                    271:             if (nref_ct > 1) {
                    272:                 /* this is a lock list */
                    273:                 char *nref;
                    274:                 char tmps[255];
                    275:                 
                    276:                 int successes = 0;
                    277:                 int attempts = 0;
                    278:                 
                    279:                 stcpy (tmps, key);
                    280:                 stcnv_m2c (tmps);                               
                    281:                 
                    282:                 nref = strtok (tmps, "\001\201");
                    283: 
                    284:                 for (;;) {                    
                    285:                     attempts++;
                    286: 
                    287:                     if (locktab_insert (nref) != NULL) {
                    288:                         successes++;
                    289:                     }
                    290:                     else {
                    291:                         locktab_decrement (nref, 0L);
                    292:                         test = 0;
                    293:                         return;
                    294:                     }
                    295:                     
                    296:                     nref = strtok (NULL, "\001\201");                    
                    297:                     if (nref == NULL) break;
                    298:                 }                        
                    299: 
                    300:                 test = 1;
                    301:                 if (tp_level > 0) tp_add_op (TRUE, lck_action, key, chk_ns);      
                    302:                 return;
                    303:               
                    304:             }
                    305:             else {
                    306:             
                    307:                 if (locktab_insert (key) != NULL) {
                    308:                     test = 1;
                    309:                     if (tp_level > 0) tp_add_op (TRUE, lck_action, key, chk_ns);
                    310:                 }
                    311:                 else {
                    312:                     test = 0;
                    313:                 }
                    314: 
                    315:             }
                    316: 
                    317:             break;
                    318: 
                    319:         case 1: /* special case: lock with 1-second timeout */
                    320: 
                    321:             if (locktab_insert (key) != NULL) {
                    322:                 test = 1;            
                    323:             }
                    324:             else {
                    325:                 sleep (1);
                    326: 
                    327:                 if (locktab_insert (key) != NULL) {
                    328:                     test = 1;
                    329:                     if (tp_level > 0) tp_add_op (TRUE, lck_action, key, chk_ns);
                    330:                 }
                    331:                 else {
                    332:                     test = 0;
                    333:                 }
                    334:             }
                    335: 
                    336:             return;
                    337:             
                    338:         default: /* lock with timeout */
                    339:         {
                    340:             time_t start_secs;
                    341:             time_t end_secs;
                    342:             time_t elapsed;
                    343:             locktab_ent_t *lck = NULL;
                    344:             
                    345:             start_secs = time (NULL);
                    346: 
                    347:             if (nref_ct > 1) {
                    348:                 /* this is a lock-list */
                    349:                 printf ("lock-list with timeout\r\n");
                    350:             }
                    351:             else {
                    352:                 
                    353:             
                    354:                 for (;;) {
                    355:                     
                    356:                     
                    357:                     lck = locktab_insert (key);
                    358:                     
                    359:                     end_secs = time (NULL);
                    360:                     elapsed = end_secs - start_secs;
                    361:                     
                    362:                     if (lck != NULL) {
                    363:                         test = 1;
                    364:                         return;
                    365:                     }
                    366:                     
                    367:                     if (elapsed >= lck_timeout) {
                    368:                         
                    369:                         if (lck == NULL) {
                    370:                             test = 0;          
                    371:                         }
                    372:                         else {
                    373:                             if (tp_level > 0) tp_add_op (TRUE, lck_action, key, chk_ns);
                    374:                             test = 1;
                    375:                         }
                    376:                         
                    377:                         return;
                    378:                         
                    379:                     }
                    380: 
                    381:                     sleep (1); /* prevent CPU pegging */
                    382:                 
                    383:                 } /* timeout loop */
                    384: 
                    385:                 return;
                    386:             }
                    387:             
                    388:         } /* lock with timeout */
                    389:     } /* switch (timeout) */
                    390:             
                    391:             
                    392: }
                    393: 
                    394: void locktab_decrement(char *key, long lck_timeout)
                    395: {
                    396: 
                    397:     locktab_ent_t *lck = locktab_find (key);
                    398:     
                    399:     if (lck != NULL) {
                    400: 
                    401:         if (tp_level > lck->tp_level) {
                    402:             merr_raise (M41);
                    403:             return;
                    404:         }
                    405:         
                    406:         if (lck->ct > 0) lck->ct--;       
                    407:         
                    408:         if (lck->ct == 0) {
                    409:             lck->owner_job = 0;
                    410:             strcpy (lck->namespace, "<REUSABLE>");
                    411: 
                    412:             ssvn_lock_remove (lck->nref);
                    413:         }
                    414: 
                    415:         if (lck->owner_job != 0) {
                    416:             ssvn_lock_add (lck->nref, lck->owner_job, lck->ct);
                    417:         }
                    418:         
                    419:     }
                    420: 
                    421:     if (lck_timeout > -1) test = 1;
                    422:     
                    423: }
                    424: 
                    425: void locktab_unlock_all(void)
                    426: {
1.7     ! snw       427:     locktab_unlock_all_by_pid (pid);
        !           428: }
        !           429: 
        !           430: void locktab_unlock_all_by_pid(const pid_t target_pid)
        !           431: {
1.1       snw       432:     locktab_ent_t *lck;
1.7     ! snw       433:     int remove_ct;
        !           434: 
        !           435:     remove_ct = 0;
        !           436:     if (target_pid != pid) {
        !           437:         logprintf (FM_LOG_INFO, "locktab_unlock_all_by_pid:  removing all locks for pid %ld", target_pid);
        !           438:     }
        !           439: 
1.1       snw       440:     
                    441:     for (lck = shm_config->hdr->locktab_head; lck != NULL; lck = lck->next) {
                    442: 
1.7     ! snw       443:         if (lck->owner_job == target_pid) {
        !           444:             remove_ct++;
        !           445:             
1.1       snw       446:             if (tp_level > lck->tp_level) {
                    447:                 merr_raise (M41);
                    448:                 return;
                    449:             }
                    450:             
                    451:             lck->ct = 0;
                    452:             lck->owner_job = 0;
                    453:             strcpy (lck->namespace, "<REUSABLE>");
                    454: 
                    455:             ssvn_lock_remove (lck->nref);
                    456:             
                    457:         }
                    458: 
1.7     ! snw       459:     }
        !           460: 
        !           461:     if (target_pid != pid) {
        !           462:         logprintf (FM_LOG_INFO, "locktab_unlock_all_by_pid:  removed %ld lock(s) for pid %ld", remove_ct, target_pid);
        !           463:     }
        !           464: 
1.1       snw       465:     
                    466: }
                    467: 
                    468: locktab_ent_t *locktab_find(char *key)
                    469: {
                    470: 
                    471:     locktab_ent_t *lck;
                    472:     char chk_ns[255];
                    473: 
                    474:     if (key[1] == '%') {
1.6       snw       475:         snprintf (chk_ns, sizeof (chk_ns) - 1, "SYSTEM");
1.1       snw       476:     }
                    477:     else {
1.6       snw       478:         snprintf (chk_ns, sizeof (chk_ns) - 1, "%s", nsname);
1.1       snw       479:     }
                    480: 
                    481:     for (lck = shm_config->hdr->locktab_head; lck != NULL; lck = lck->next) {
                    482: 
                    483:         if ((stcmp (lck->nref, key) == 0) && (strcmp (lck->namespace, chk_ns) == 0)) {
                    484: 
                    485:             if (lck->owner_job != pid) {
                    486:                 return (locktab_ent_t *) NULL;
                    487:             }
                    488:             else {
                    489:                 return lck;
                    490:             }
                    491:             
                    492:         }
                    493:         
                    494:     }
                    495: 
                    496:     return (locktab_ent_t *) NULL;
                    497:     
                    498: }
                    499: 
                    500: locktab_ent_t *locktab_insert(char *key)
                    501: {
                    502:     locktab_ent_t *l;
                    503:     char chk_ns[255];
                    504: 
                    505:     freem_ref_t *ik;
                    506:     freem_ref_t *ok;
                    507:     
                    508:     ik = malloc (sizeof (freem_ref_t));
                    509:     NULLPTRCHK(ik,"locktab_insert");
                    510: 
                    511:     ik = mref_init (ik, MREF_RT_GLOBAL, "");
                    512: 
                    513:     ok = malloc (sizeof (freem_ref_t));
                    514:     NULLPTRCHK(ok,"locktab_insert");    
                    515: 
                    516:     ik = internal_to_mref (ik, key);
                    517:     
                    518:     if (key[1] == '%') {
1.6       snw       519:         snprintf (chk_ns, sizeof (chk_ns) - 1, "SYSTEM");
1.1       snw       520:     }
                    521:     else {
1.6       snw       522:         snprintf (chk_ns, sizeof (chk_ns) - 1, "%s", nsname);
1.1       snw       523:     }
                    524:     
                    525:     for (l = shm_config->hdr->locktab_head; l != NULL; l = l->next) {
                    526:         ok = mref_init (ok, MREF_RT_GLOBAL, "");
                    527:         ok = internal_to_mref (ok, l->nref);
                    528:         
                    529:         if (((stcmp (l->nref, key) == 0) || (mref_is_descendant (ok, ik) == TRUE)) && (strcmp (l->namespace, chk_ns) == 0)) {
                    530:             
                    531:             /* nref already owned by another job */
                    532:             if ((l->owner_job != pid) && (l->ct > 0)) {
                    533:                 free (ik);
                    534:                 free (ok);
                    535:                 return NULL;
                    536:             }
                    537:             else {
                    538:                 if ((mref_is_descendant (ok, ik)) && (pid == l->owner_job)) {
                    539:                     if (locktab_find (key) == NULL) goto new_insert;
                    540:                 }
                    541:                 
                    542:                 /* increment the lock and return */
                    543:                 l->ct++;
                    544: 
                    545:                 /* if this was a lock with a counter of zero belonging to another pid,
                    546:                  * re-use it and take ownership of it.
                    547:                  */
                    548:                 if (l->owner_job != pid) l->owner_job = pid;
                    549: 
                    550:                 l->tp_level = tp_level;
                    551:                 
                    552:                 ssvn_lock_add (l->nref, l->owner_job, l->ct);
                    553: 
                    554:                 free (ik);
                    555:                 free (ok);
                    556:                 
                    557:                 return l;
                    558:             }
                    559:             
                    560:         }
                    561: 
                    562:     }
                    563: 
                    564: new_insert:
                    565:     /* no lock exists for key: this is a new insert */            
                    566:     l = (locktab_ent_t *) shm_alloc (sizeof (locktab_ent_t));
                    567:     if (l == (locktab_ent_t *) NULL) {
                    568:         free (ik);
                    569:         free (ok);
                    570:         return (locktab_ent_t *) NULL;
                    571:     }
                    572: 
                    573:     stcpy (l->nref, key);
1.6       snw       574:     snprintf (l->namespace, sizeof (l->namespace) - 1, "%s", chk_ns);
1.1       snw       575:         
                    576:     l->owner_job = pid;
                    577:     l->ct = 1;
                    578:     
                    579:     l->next = shm_config->hdr->locktab_head;
                    580:     shm_config->hdr->locktab_head = l;
                    581: 
                    582:     ssvn_lock_add (l->nref, l->owner_job, l->ct);
                    583: 
                    584:     free (ik);
                    585:     free (ok);
                    586:     
                    587:     return l;
                    588: }
                    589: 
                    590: 
                    591: int locktab_count(char *key)
                    592: {
                    593:     locktab_ent_t *l;
                    594:     int ct = 0;
                    595: 
                    596:     for (l = shm_config->hdr->locktab_head; l != NULL; l = l->next) {
                    597:         if (stcmp (l->nref, key) == 0) ct++;
                    598:     }
                    599: 
                    600:     return ct;
                    601: }
                    602: 
                    603: int locktab_list_count(char *key)
                    604: {
                    605:     int i;
                    606:     int lct = 0;
                    607:     
                    608:     for (i = 0; i < stlen (key); i++) {
                    609:         if (key[i] == '\001') lct++;        
                    610:     }
                    611: 
                    612:     return lct;
                    613: }
                    614: 
                    615: unsigned long locktab_pages(void)
                    616: {
                    617: 
                    618:     locktab_ent_t *l;
                    619:     unsigned long bytes = 0;
                    620:     unsigned long pages = 0;
                    621:     float extra;
                    622:     
                    623:     for (l = shm_config->hdr->locktab_head; l != NULL; l = l->next) {
                    624:         bytes += sizeof (locktab_ent_t);
                    625:     }
                    626: 
                    627:     pages = bytes / PG_SIZE;
                    628:     extra = bytes % PG_SIZE;
                    629:     
                    630:     if (extra > 0) {
                    631:         pages++;
                    632:     }
                    633: 
                    634:     return pages;
                    635:   
                    636: }
                    637: 
                    638: unsigned long locktab_bytes(void)
                    639: {
                    640: 
                    641:     locktab_ent_t *l;
                    642:     unsigned int ct = 0;
                    643:     unsigned long bytes = 0;
                    644: 
                    645:     for (l = shm_config->hdr->locktab_head; l != NULL; l = l->next) {
                    646:         ct++;
                    647:         bytes += sizeof (locktab_ent_t);
                    648:     }
                    649: 
                    650:     return bytes;
                    651: 
                    652: }
                    653: 
                    654: void locktab_dump(void)
                    655: {
                    656:     
                    657:     locktab_ent_t *l;
                    658:     unsigned long ct = 0;
                    659:     unsigned long tot = 0;
                    660:     freem_ref_t *r;
                    661:     char *ref_ext;
                    662:     
                    663:     r = (freem_ref_t *) malloc (sizeof (freem_ref_t));
                    664:     NULLPTRCHK(r,"locktab_dump");
                    665: 
                    666:     ref_ext = (char *) malloc (STRLEN * sizeof (char));
                    667:     NULLPTRCHK(ref_ext,"locktab_dump");
                    668:     
                    669:     printf ("%-20s%-20s%-20s%s\r\n", "NAMESPACE", "PID", "COUNT", "KEY");
                    670:     printf ("%-20s%-20s%-20s%s\r\n", "---------", "---", "-----", "---");
                    671: 
                    672:     if (shm_config->hdr->locktab_head == NULL) {
                    673:         printf ("\r\n*** lock table empty ***\r\n");
                    674:         free (r);
                    675:         return;
                    676:     }
                    677: 
                    678:     
                    679:     for (l = shm_config->hdr->locktab_head; l != NULL; l = l->next) {
                    680: 
                    681:         mref_init (r, MREF_RT_GLOBAL, "");
                    682:         internal_to_mref (r, l->nref);
                    683:         mref_to_external (r, ref_ext);
                    684: 
                    685:         if (l->owner_job) {
                    686:             printf ("%-20s%-20d%-20d%s\r\n", l->namespace, l->owner_job, l->ct, ref_ext);
                    687:             ct++;
                    688:         }
                    689:         
                    690:         tot++;
                    691:         
                    692:     }
                    693: 
                    694:     printf ("\r\n\tActive LOCK table entries:            %ld\r\n", ct);
                    695:     printf (    "\tReusable LOCK table entries:          %ld\r\n", tot - ct);
                    696:     printf (    "\tShared memory pages:                  %ld\r\n", locktab_pages ());
                    697:     printf (    "\tShared memory bytes:                  %ld\r\n", locktab_bytes ());
                    698: 
                    699:     free (r);
                    700:     free (ref_ext);
                    701:     
                    702:     return;
                    703:     
                    704: }

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