Diff for /freem/src/shmmgr.c between versions 1.1 and 1.18

version 1.1, 2025/01/19 02:04:04 version 1.18, 2025/05/16 04:25:15
Line 1 Line 1
 /*  /*
  *                            *   *   $Id$
  *                           * *  
  *                          *   *  
  *                     ***************  
  *                      * *       * *  
  *                       *  MUMPS  *  
  *                      * *       * *  
  *                     ***************  
  *                          *   *  
  *                           * *  
  *                            *  
  *  
  *   shmmgr.c  
  *    shared memory manager   *    shared memory manager
  *   *
  *     *  
  *   Author: Serena Willis <jpw@coherent-logic.com>   *   Author: Serena Willis <snw@coherent-logic.com>
  *    Copyright (C) 1998 MUG Deutschland   *    Copyright (C) 1998 MUG Deutschland
  *    Copyright (C) 2020 Coherent Logic Development LLC   *    Copyright (C) 2020, 2025 Coherent Logic Development LLC
  *   *
  *   *
  *   This file is part of FreeM.   *   This file is part of FreeM.
Line 35 Line 23
  *   You should have received a copy of the GNU Affero Public License   *   You should have received a copy of the GNU Affero Public License
  *   along with FreeM.  If not, see <https://www.gnu.org/licenses/>.   *   along with FreeM.  If not, see <https://www.gnu.org/licenses/>.
  *   *
    *   $Log$
    *   Revision 1.18  2025/05/16 04:25:15  snw
    *   Make shm seed NULL on ARM
    *
    *   Revision 1.17  2025/05/12 18:18:00  snw
    *   Further work on shared memory
    *
    *   Revision 1.16  2025/05/12 14:26:15  snw
    *   Revert bad change in shared memory manager
    *
    *   Revision 1.15  2025/05/09 19:44:50  snw
    *   Begin shm rework
    *
    *   Revision 1.14  2025/05/08 14:47:26  snw
    *   Break everything to begin shared memory rewrite
    *
    *   Revision 1.13  2025/04/16 17:36:12  snw
    *   Add FreeBSD shm cleanup script
    *
    *   Revision 1.12  2025/04/15 21:57:10  snw
    *   Fix SysV IPC bugs on FreeBSD
    *
    *   Revision 1.11  2025/04/15 21:08:51  snw
    *   Add some useful debug output
    *
    *   Revision 1.10  2025/04/15 19:26:13  snw
    *   Remove extra whitespace
    *
    *   Revision 1.9  2025/04/15 16:49:36  snw
    *   Make use of logprintf throughout codebase
    *
    *   Revision 1.8  2025/04/14 19:46:18  snw
    *   Add SHM_REMAP flag to shmat on FreeBSD
    *
    *   Revision 1.7  2025/04/09 19:52:02  snw
    *   Eliminate as many warnings as possible while building with -Wall
    *
    *   Revision 1.6  2025/04/04 19:43:18  snw
    *   Switch to using environment catalog to determine user and group for environment, and remove -u and -g flags from freem
    *
    *   Revision 1.5  2025/03/24 02:56:50  snw
    *   Shared memory compatibility fixes for OS/2
    *
    *   Revision 1.4  2025/03/09 19:50:47  snw
    *   Second phase of REUSE compliance and header reformat
    *
    *
    * SPDX-FileCopyrightText:  (C) 2025 Coherent Logic Development LLC
    * SPDX-License-Identifier: AGPL-3.0-or-later
  **/   **/
   
 #include <stdlib.h>  #include <stdlib.h>
Line 48 Line 85
 #include "shmmgr.h"  #include "shmmgr.h"
 #include "mpsdef.h"  #include "mpsdef.h"
 #include "locktab.h"  #include "locktab.h"
   #include "log.h"
   
 #include <sys/types.h>  #include <sys/types.h>
 #include <sys/ipc.h>  #include <sys/ipc.h>
 #include <sys/sem.h>  #include <sys/sem.h>
   
 #if !defined(__OpenBSD__) && !defined(__APPLE__)  #if !defined(__OpenBSD__) && !defined(__APPLE__) && !defined(__OS2__)
 union semun {  union semun {
     int              val;    /* Value for SETVAL */      int              val;    /* Value for SETVAL */
     struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */      struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
Line 73  void shm_daemon_init(void); Line 111  void shm_daemon_init(void);
   
 shm_config_t *shm_config = (shm_config_t *) NULL;  shm_config_t *shm_config = (shm_config_t *) NULL;
   
   #if defined(__FreeBSD__)
   # define FM_SHM_PERMS 0777
   #else
   # define FM_SHM_PERMS 0770
   #endif
   
 short shm_init(const size_t seg_size)  short shm_init(const size_t seg_size)
 {  {
     union semun arg;  
     size_t alloc_map_size;      size_t alloc_map_size;
     long pg_size;      long pg_size;
     register int i;  
     key_t shm_sk;      key_t shm_sk;
       
   #if defined(__FreeBSD__)
       struct shmid_ds ctl;
   #endif
       
     shm_sk = ftok (config_file, 5);          shm_sk = ftok (config_file, 5);    
     pg_size = sysconf (_SC_PAGESIZE);      pg_size = sysconf (_SC_PAGESIZE);
           
Line 88  short shm_init(const size_t seg_size) Line 134  short shm_init(const size_t seg_size)
     NULLPTRCHK(shm_config,"shm_init");          NULLPTRCHK(shm_config,"shm_init");    
           
     /* figure out how many pages we can fit in the segment, accounting for header size */      /* figure out how many pages we can fit in the segment, accounting for header size */
     shm_config->pgct = (seg_size / pg_size) - sizeof (shm_hdr_t);      shm_config->pgct = (seg_size - sizeof (shm_hdr_t)) / pg_size;
           
     /* how big will the alloc map be? */      /* how big will the alloc map be? */
     alloc_map_size = shm_config->pgct * sizeof (shm_page_t);      alloc_map_size = shm_config->pgct * sizeof (shm_page_t);
Line 96  short shm_init(const size_t seg_size) Line 142  short shm_init(const size_t seg_size)
     shm_config->segsiz = seg_size + alloc_map_size + pg_size;      shm_config->segsiz = seg_size + alloc_map_size + pg_size;
     shm_config->key = ftok (config_file, 1);      shm_config->key = ftok (config_file, 1);
     shm_config->pgsiz = pg_size;      shm_config->pgsiz = pg_size;
              
     shm_config->seg_id = shmget (shm_config->key, shm_config->segsiz, 0660 | IPC_CREAT);      shm_config->seg_id = shmget (shm_config->key, shm_config->segsiz, FM_SHM_PERMS | IPC_CREAT);
     if (shm_config->seg_id == -1) {      if (shm_config->seg_id == -1) {
         if (errno == 22) {          if (errno == 22) {
             fprintf (stderr, "shm_init:  cannot get shared memory segment of %d bytes\r\n\r\n", shm_config->segsiz);              logprintf (FM_LOG_ERROR, "shm_init:  cannot get shared memory segment of %ld bytes", (unsigned long) shm_config->segsiz);
             fprintf (stderr, "You may need to tune your kernel parameters, or manually set a smaller shared memory segment size in both the FreeM daemon and each interpreter process by using the `-S` command-line flag.\r\n\r\nPlease refer to the FreeM Platform Notes for your operating system for details.\r\n\r\n");               fprintf (stderr, "\r\nYou may need to tune your kernel parameters, or manually set a smaller shared memory segment size in both the FreeM daemon and each interpreter process by using the `-S` command-line flag.\r\n\r\nPlease refer to the FreeM Platform Notes for your operating system for details.\r\n"); 
         }          }
         return SHMS_GET_ERR;          return SHMS_GET_ERR;
     }      }
   
 #if !defined(__arm__)      
     shm_config->dta = shmat (shm_config->seg_id, NULL, 0);      shm_config->dta = shmat (shm_config->seg_id, NULL, 0);
 #else  
     shm_config->dta = shmat (shm_config->seg_id, (void *) 0x1000000, 0);  
 #endif  
           
     if (shm_config->dta == (void *) -1) {           if (shm_config->dta == (void *) -1) {     
         return SHMS_ATTACH_ERR;          logprintf (FM_LOG_FATAL, "shm_init:  shmat() failed (error code %d [%s])", errno, strerror (errno));
     }      }
     /* view the first sizeof (shm_hdr_t) bytes of the data area as an shm_hdr_t */      /* view the first sizeof (shm_hdr_t) bytes of the data area as an shm_hdr_t */
     shm_config->hdr = (shm_hdr_t *) shm_config->dta;      shm_config->hdr = (shm_hdr_t *) shm_config->dta;
Line 135  short shm_init(const size_t seg_size) Line 177  short shm_init(const size_t seg_size)
         daemon_chk = kill (shm_config->hdr->first_process, 0);          daemon_chk = kill (shm_config->hdr->first_process, 0);
   
         if (daemon_chk == -1 && errno == ESRCH) {          if (daemon_chk == -1 && errno == ESRCH) {
               logprintf (FM_LOG_WARNING, "shm_init:  recovering from crashed daemon pid %ld", shm_config->hdr->first_process);
             fprintf (stderr, "shm_init:  recovering from crashed daemon pid %d\r\n", shm_config->hdr->first_process);  
   
             first_process = TRUE;              first_process = TRUE;
   
             shm_daemon_init ();              shm_daemon_init ();
   
         }          }
         else {          else {
           
   
             first_process = FALSE;              first_process = FALSE;
   
             semid_shm = semget (shm_sk, 1, 0);              semid_shm = semget (shm_sk, 1, 0);
             if (semid_shm == -1) {              if (semid_shm == -1) {
                 fprintf (stderr, "shm_init:  could not attach to shared memory semaphore\r\n");                  logprintf (FM_LOG_FATAL, "shm_init:  could not attach to shared memory semaphore [%s]", strerror (errno));         
                 exit (1);  
             }              }
                           
             /* we are NOT the initial process. if addresses don't match, re-attach! */              shm_config->buf = SHMALIGN(shm_config->dta + (sizeof (shm_hdr_t) * shm_config->pgct));
             /* (again, borrowed from RSM) */  
             if (shm_config->hdr->shmad != shm_config->dta) {  
                   
                 /* grab the pointers we need */  
                 void *old_addr = shm_config->dta;  
                 void *new_addr = shm_config->hdr->shmad;  
                   
                 /* detach and reattach */  
                 if (shmdt (old_addr) == -1) {  
                     fprintf (stderr, "shm_init:  detach failed during detach/reattach [shmdt error %s]\r\n", strerror (errno));  
                     exit (1);  
                 }  
                   
                 shm_config->dta = shmat (shm_config->seg_id, new_addr, 0);  
   
                 if (shm_config->dta == (void *) -1) {  
                     fprintf (stderr, "shm_init:  fatal error attaching shared memory segment [shmat error '%s']\r\n", strerror (errno));  
                     exit (1);  
                 }  
                   
                 shm_config->hdr = (shm_hdr_t *) shm_config->dta;  
   
                 /* allocator buffer at the next page-aligned address after the header and allocation map */  
                 shm_config->buf = SHMALIGN(shm_config->dta + (sizeof (shm_hdr_t) * shm_config->pgct));  
             }  
             else {  
                 shm_config->buf = SHMALIGN(shm_config->dta + (sizeof (shm_hdr_t) * shm_config->pgct));  
             }  
           
         }          }
   
     }      }
Line 199  short shm_init(const size_t seg_size) Line 205  short shm_init(const size_t seg_size)
 void shm_daemon_init(void)  void shm_daemon_init(void)
 {  {
     union semun arg;      union semun arg;
     size_t alloc_map_size;  
     key_t shm_sk;      key_t shm_sk;
     register int i;      register int i;
   
Line 207  void shm_daemon_init(void) Line 212  void shm_daemon_init(void)
           
     semid_shm = semget (shm_sk, 1, 0660 | IPC_CREAT);      semid_shm = semget (shm_sk, 1, 0660 | IPC_CREAT);
     if (semid_shm == -1) {      if (semid_shm == -1) {
         fprintf (stderr, "shm_init:  failed to create shared memory semaphore\r\n");          logprintf (FM_LOG_FATAL, "shm_init:  failed to create shared memory semaphore [%s]", strerror (errno));
         exit (1);  
     }      }
           
     arg.val = 1;      arg.val = 1;
     if (semctl (semid_shm, 0, SETVAL, arg) == -1) {      if (semctl (semid_shm, 0, SETVAL, arg) == -1) {
         fprintf (stderr, "shm_init:  failed to initialize shared memory semaphore\r\n");          logprintf (FM_LOG_FATAL, "shm_init:  failed to initialize shared memory semaphore [%s]", strerror (errno));  
         exit (1);  
     }      }
           
     /* zero out the segment */      /* zero out the segment */
Line 233  void shm_daemon_init(void) Line 236  void shm_daemon_init(void)
     shm_config->alloc_map = (shm_page_t *) (shm_config->dta + sizeof (shm_hdr_t));      shm_config->alloc_map = (shm_page_t *) (shm_config->dta + sizeof (shm_hdr_t));
 */      */    
     shm_config->buf = SHMALIGN(shm_config->dta + (sizeof (shm_hdr_t) * shm_config->pgct));      shm_config->buf = SHMALIGN(shm_config->dta + (sizeof (shm_hdr_t) * shm_config->pgct));
     printf ("shm_daemon_init:  allocator buffer aligned at %p (system page size %ld)\r\n", shm_config->buf, sysconf (_SC_PAGESIZE));      logprintf (FM_LOG_INFO, "shm_daemon_init:  allocator buffer aligned at %p (system page size %ld)", shm_config->buf, sysconf (_SC_PAGESIZE));
           
     for (i = 0; i < shm_config->pgct; i++) {      for (i = 0; i < shm_config->pgct; i++) {
         shm_config->hdr->alloc_map[i].is_first = FALSE;          shm_config->hdr->alloc_map[i].is_first = FALSE;
Line 251  short shm_exit(void) Line 254  short shm_exit(void)
     res = shmdt (shm_config->dta);      res = shmdt (shm_config->dta);
   
     if (res == -1) {      if (res == -1) {
         fprintf (stderr, "shm_exit:  failure in shmdt()\r\n");          logprintf (FM_LOG_ERROR, "shm_exit:  failure in shmdt() [%s]", strerror (errno));
         return FALSE;          return FALSE;
     }      }
           
Line 260  short shm_exit(void) Line 263  short shm_exit(void)
         res = shmctl (shm_config->seg_id, IPC_RMID, 0);          res = shmctl (shm_config->seg_id, IPC_RMID, 0);
   
         if (res == -1) {          if (res == -1) {
             fprintf (stderr, "shm_exit:  failure in shmctl()\r\n");              logprintf (FM_LOG_ERROR, "shm_exit:  failure in shmctl() [%s]", strerror (errno));
             return FALSE;              return FALSE;
         }          }
   
Line 346  void *shm_alloc_pages(const int page_cou Line 349  void *shm_alloc_pages(const int page_cou
     shm_page_t *pg;      shm_page_t *pg;
   
     if (shm_get_sem () == FALSE) {      if (shm_get_sem () == FALSE) {
         fprintf (stderr, "shm_alloc_pages:  could not get exclusive access to shared memory\r\n");          logprintf (FM_LOG_FATAL, "shm_alloc_pages:  could not get exclusive access to shared memory");
         exit (1);  
     }      }
   
           
Line 422  void shm_free_page(const int page_number Line 424  void shm_free_page(const int page_number
     shm_page_t *a = shm_get_alloc_map_entry (page_number);      shm_page_t *a = shm_get_alloc_map_entry (page_number);
   
     if (a->is_first == FALSE) {      if (a->is_first == FALSE) {
         fprintf (stderr, "shm_free_page:  attempt to free page in the middle of allocation chain\r\n");          logprintf (FM_LOG_ERROR, "shm_free_page:  attempt to free page in the middle of allocation chain");
         return;          return;
     }      }
   
     if (a->pg_state == PG_FREE) {      if (a->pg_state == PG_FREE) {
         fprintf (stderr, "shm_free_page:  double free attempted in page %d\r\n", page_number);          logprintf (FM_LOG_FATAL, "shm_free_page:  double free attempted in page %d", page_number);
         exit (1);  
     }      }
           
     if (shm_get_sem () == FALSE) {      if (shm_get_sem () == FALSE) {
         fprintf (stderr, "shm_free_page:  could not get exclusive access to shared memory\r\n");          logprintf (FM_LOG_FATAL, "shm_free_page:  could not get exclusive access to shared memory");
         exit (1);  
     }      }
   
           
Line 473  void shm_dump(void) Line 473  void shm_dump(void)
 {  {
   
     printf ("SHARED MEMORY CONFIGURATION\r\n");      printf ("SHARED MEMORY CONFIGURATION\r\n");
     printf ("  pgsiz                   %d\r\n", shm_config->pgsiz);      printf ("  pgsiz                   %ld\r\n", (unsigned long) shm_config->pgsiz);
     printf ("  pgct                    %d\r\n", shm_config->pgct);      printf ("  pgct                    %d\r\n", shm_config->pgct);
     printf ("  key                     %d\r\n", shm_config->key);      printf ("  key                     %d\r\n", shm_config->key);
     printf ("  segid                   %d\r\n", shm_config->seg_id);      printf ("  segid                   %d\r\n", shm_config->seg_id);
     printf ("  sizeof shm_page_t       %d\r\n", sizeof (shm_page_t));      printf ("  sizeof shm_page_t       %ld\r\n", (long) sizeof (shm_page_t));
     printf ("  segsiz                  %d\r\n", shm_config->segsiz);      printf ("  segsiz                  %ld\r\n", (long) shm_config->segsiz);
     printf ("  shm address             %p\r\n", shm_config->dta);      printf ("  shm address             %p\r\n", shm_config->dta);
     printf ("  alloc_map size          %d\r\n", sizeof (shm_page_t) * shm_config->pgct);      printf ("  alloc_map size          %ld\r\n", (unsigned long) sizeof (shm_page_t) * shm_config->pgct);
     printf ("  buf address             %p\r\n", shm_config->buf);      printf ("  buf address             %p\r\n", shm_config->buf);
 }  }
   

Removed from v.1.1  
changed lines
  Added in v.1.18


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