Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Enduro/X Standard Library Shared memory commons
0003  *   For some history. Some parts are moved here from libatmi, for the System V
0004  *   support. System V queues uses some SHM/SEM parts for the qid mappings to
0005  *   Posix queues.
0006  *   This implementation uses System V shared memory interfaces, due to some
0007  *   nasty issues with Oracle Solaris... See Support #355
0008  *
0009  * @file nstd_shmsv.c
0010  */
0011 /* -----------------------------------------------------------------------------
0012  * Enduro/X Middleware Platform for Distributed Transaction Processing
0013  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0014  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0015  * This software is released under one of the following licenses:
0016  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0017  * See LICENSE file for full text.
0018  * -----------------------------------------------------------------------------
0019  * AGPL license:
0020  *
0021  * This program is free software; you can redistribute it and/or modify it under
0022  * the terms of the GNU Affero General Public License, version 3 as published
0023  * by the Free Software Foundation;
0024  *
0025  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0026  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0027  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0028  * for more details.
0029  *
0030  * You should have received a copy of the GNU Affero General Public License along 
0031  * with this program; if not, write to the Free Software Foundation, Inc.,
0032  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0033  *
0034  * -----------------------------------------------------------------------------
0035  * A commercial use license is available from Mavimax, Ltd
0036  * contact@mavimax.com
0037  * -----------------------------------------------------------------------------
0038  */
0039 
0040 /*---------------------------Includes-----------------------------------*/
0041 
0042 #include <stdlib.h>
0043 #include <stdio.h>
0044 
0045 /* shm_* stuff, and mmap() */
0046 #include <sys/mman.h>
0047 #include <sys/types.h>
0048 #include <sys/ipc.h>
0049 #include <sys/shm.h>
0050 /* exit() etc */
0051 #include <unistd.h>
0052 #include <fcntl.h>
0053 #include <sys/stat.h>
0054 
0055 #include <ndrstandard.h>
0056 #include <ndebug.h>
0057 #include <nstd_shm.h>
0058 
0059 #include "sys_unix.h"
0060 
0061 
0062 /*---------------------------Externs------------------------------------*/
0063 /*---------------------------Macros-------------------------------------*/
0064 /*---------------------------Enums--------------------------------------*/
0065 /*---------------------------Typedefs-----------------------------------*/
0066 typedef struct
0067 {
0068     char *suffix;
0069     int idx;
0070 } segmap_t;
0071     
0072 /*---------------------------Globals------------------------------------*/
0073 /*---------------------------Statics------------------------------------*/
0074 exprivate segmap_t M_map[] = {
0075         {NDRX_SHM_SRVINFO_SFX, NDRX_SHM_SRVINFO_KEYOFSZ}
0076         ,{NDRX_SHM_SVCINFO_SFX, NDRX_SHM_SVCINFO_KEYOFSZ}
0077         ,{NDRX_SHM_BRINFO_SFX, NDRX_SHM_BRINFO_KEYOFSZ}
0078         ,{NDRX_SHM_P2S_SFX, NDRX_SHM_P2S_KEYOFSZ}
0079         ,{NDRX_SHM_S2P_SFX, NDRX_SHM_S2P_KEYOFSZ}
0080         ,{NDRX_SHM_CPM_SFX, NDRX_SHM_CPM_KEYOFSZ}
0081         ,{NDRX_SHM_LCF_SFX, NDRX_SHM_LCF_KEYOFSZ}
0082         ,{NDRX_SHM_ROUTCRIT_SFX, NDRX_SHM_ROUTCRIT_KEYOFSZ}
0083         ,{NDRX_SHM_ROUTSVC_SFX, NDRX_SHM_ROUTSVC_KEYOFSZ}
0084         ,{NULL}
0085     };
0086 /*---------------------------Prototypes---------------------------------*/    
0087     
0088 /**
0089  * Make key out of string. Gen
0090  * @param k string to hash
0091  * @return hash value
0092  */
0093 expublic unsigned int ndrx_hash_fn( void *k )
0094 {
0095     unsigned int hash = 5381;
0096     int c;
0097     char *str = (char *)k;
0098 
0099     while ((c = *str++))
0100         hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
0101 
0102     return hash;
0103 }
0104 
0105 /**
0106  * Returns true if currently attached to shm
0107  * WARNING: This assumes that fd 0 could never be used by shm!
0108  * @return TRUE/FALSE
0109  */
0110 expublic int ndrx_shm_is_attached(ndrx_shm_t *shm)
0111 {
0112     int ret=EXTRUE;
0113     
0114     if (NULL==shm->mem || (void *)EXFAIL==shm->mem)
0115     {
0116         ret=EXFALSE;
0117     }
0118 
0119     return ret;
0120 }
0121 
0122 /**
0123  * Open shared memory segment. The path and size must be filled in shm handler
0124  * !!!! WARNING FOR NON NDRXD MODE !!!! 
0125  * If there could be some race condition, if several binaries are started
0126  * in the same time and they attempt to create a shared memory blocks.
0127  * of course it is not normal mode of operations, we use that only for testing
0128  * thus be aware, maybe some test cases needs to be tuned with some sleep periods.
0129  * NOTE ! We need early logger, as this is open from LCF init.
0130  * @param shm shm handler. path and size must be set.
0131  * @param attach_on_exists if shm exists, perform attach instead of failure
0132  * @return EXSUCCEED/EXFAIL
0133  */
0134 expublic int ndrx_shm_open(ndrx_shm_t *shm, int attach_on_exists)
0135 {
0136     int ret=EXSUCCEED;
0137     
0138     /* creating the shared memory object --  shm_open() */
0139     shm->fd = shmget(shm->key, shm->size, IPC_CREAT | IPC_EXCL| S_IRWXU | S_IRWXG);
0140 
0141     if (shm->fd < 0)
0142     {
0143         int err = errno;
0144         
0145         /* if failed to create with EEXISTS error, try to attach */
0146         
0147         if (EEXIST==err && attach_on_exists)
0148         {
0149             NDRX_LOG_EARLY(log_info, "Shared memory exists [%s]/%x - attaching",
0150                     shm->path, shm->key);
0151             return ndrx_shm_attach(shm);
0152         }
0153         
0154         NDRX_LOG_EARLY(log_error, "Failed to create shm [%s]: %s",
0155                             shm->path, strerror(err));
0156         EXFAIL_OUT(ret);
0157     }
0158     
0159     shm->mem = (char *)shmat(shm->fd, 0, 0);
0160     
0161     if ((void *)EXFAIL==shm->mem)
0162     {
0163         NDRX_LOG_EARLY(log_error, "Failed to shmat memory for [%s] fd %d/%x bytes %d: %s",
0164                             shm->path, shm->fd, shm->key, shm->size, strerror(errno));
0165         EXFAIL_OUT(ret);
0166     }
0167     
0168     /**
0169      *  Reset SHM 
0170      * In case of some processes are doing attach, here race condition
0171      * is possible, as memory is ready, other process may already connect
0172      * and even advertise something, but we reset it here.
0173      * so this is redundant, as SUS says, that created memory will be already
0174      * initialized to 0.
0175     memset(shm->mem, 0, shm->size);
0176      * */
0177     
0178     NDRX_LOG_EARLY(log_info, "Shm: [%s] %d/%x created size: %d mem: %p", 
0179             shm->path, shm->fd, shm->key, shm->size, shm->mem);
0180     
0181 out:
0182     /*
0183      * Should close the SHM if failed to open.
0184      */
0185     if (EXSUCCEED!=ret && EXFAIL!=shm->fd)
0186     {
0187         ndrx_shm_remove(shm);
0188     }
0189 
0190     NDRX_LOG_EARLY(log_debug, "return %d", ret);
0191 
0192     return ret;
0193 }
0194 
0195 /**
0196  * Attach to shared memory block
0197  * @param shm shared memory block
0198  * @return EXSUCCEED/EXFAIL
0199  */
0200 expublic int ndrx_shm_attach(ndrx_shm_t *shm)
0201 {
0202     int ret=EXSUCCEED;
0203     
0204     if (ndrx_shm_is_attached(shm))
0205     {
0206         NDRX_LOG_EARLY(log_debug, "shm [%s] %d/%x size: %d already attached", shm->path,
0207                 shm->fd, shm->key, shm->size);
0208         goto out;
0209     }
0210     
0211     /* Attach to shared memory block */
0212     shm->fd = shmget(shm->key, shm->size, S_IRWXU | S_IRWXG);
0213 
0214     if (shm->fd < 0) 
0215     {
0216         NDRX_LOG_EARLY(log_error, "Failed to shmget/attach shm key=%x [%s]: %s",
0217                             shm->key, shm->path, strerror(errno));
0218         EXFAIL_OUT(ret);
0219     }
0220 
0221     shm->mem = (char *)shmat(shm->fd, 0, 0);
0222     
0223     if (MAP_FAILED==shm->mem)
0224     {
0225         NDRX_LOG_EARLY(log_error, "Failed to shmat memory for [%s] fd %d/%x bytes %d: %s",
0226                             shm->path, shm->fd, shm->key, shm->size, strerror(errno));
0227         EXFAIL_OUT(ret);
0228     }
0229     
0230     NDRX_LOG_EARLY(log_debug, "Shm: [%s] %d/%x attach size: %d mem: %p", 
0231             shm->path, shm->fd, shm->key, shm->size, shm->mem);
0232 
0233 out:
0234     /*
0235      * Should close the SHM if failed to open.
0236      
0237     if (EXSUCCEED!=ret)
0238     {
0239         shm->fd=EXFAIL;
0240     }
0241     */
0242             
0243     NDRX_LOG_EARLY(log_debug, "return %d", ret);
0244 
0245     return ret;
0246 }
0247 
0248 /**
0249  * Close opened shared memory segment.
0250  * @return EXSUCCEED/EXFAIL
0251  */
0252 expublic int ndrx_shm_close(ndrx_shm_t *shm)
0253 {
0254     int ret=EXSUCCEED;
0255 
0256     if ((void *)EXFAIL==shm->mem || NULL==shm->mem)
0257     {
0258         NDRX_LOG_EARLY(log_debug, "[%s] %x already closed", shm->path, shm->key);
0259     }
0260     else 
0261     {
0262         ret = shmdt(shm->mem);
0263         
0264         if (EXSUCCEED!=ret)
0265         {
0266             NDRX_LOG_EARLY(log_error, "Failed to detach shm [%s] %d/%x addr [%p]: %d - %s",
0267                         shm->path, shm->fd, shm->key, shm->mem, errno, strerror(errno));
0268         }
0269         else
0270         {
0271             shm->mem = NULL;
0272         }
0273     }
0274 
0275 out:
0276     return ret;
0277 }
0278 
0279 /**
0280  * Remove/unlink shared memory resource
0281  * @return EXSUCCEED/EXFAIL
0282  */
0283 expublic int ndrx_shm_remove(ndrx_shm_t *shm)
0284 {
0285     int ret=EXSUCCEED;
0286     int fd;
0287     
0288     /* do not check the size... */
0289     if (EXFAIL!=(fd = shmget(shm->key, 0, S_IRWXU | S_IRWXG)))
0290     {
0291         if (EXSUCCEED!=shmctl(fd, IPC_RMID, NULL))
0292         {
0293             NDRX_LOG_EARLY(log_error, "Failed to IPC_RMID %d/%x: [%s]: %s",
0294                             fd, shm->key, shm->path, strerror(errno));
0295             ret = EXFAIL;
0296         }
0297         /* Mark memory as removed; */
0298         shm->fd = EXFAIL;
0299         shm->mem = NULL;
0300     }
0301     else
0302     {
0303         NDRX_LOG_EARLY(log_warn, "Failed to remove: [%s] %x", shm->path, shm->key);
0304     }
0305     
0306     return ret;
0307 }
0308 
0309 /**
0310  * Get shared memory key from the path
0311  * @param path
0312  * @return 
0313  */
0314 exprivate key_t keygetshm(char *path, key_t ipckey)
0315 {
0316     char *p;
0317     key_t ret;
0318     segmap_t *pp;
0319     
0320     if (NULL==(p = strchr(path, NDRX_FMT_SEP)))
0321     {
0322         NDRX_LOG(log_error, "Failed to get suffix for memory segment [%s]", 
0323                 path);
0324         EXFAIL_OUT(ret);
0325     }
0326     
0327     /* next after comma */
0328     p++;
0329     
0330     pp = M_map;
0331     
0332     while (NULL!=pp->suffix)
0333     {
0334         if (0==strcmp(pp->suffix, p))
0335         {
0336             break;
0337         }
0338         pp++;
0339     }
0340     
0341     if (NULL==pp->suffix)
0342     {
0343         NDRX_LOG(log_error, "Failed to map shared memory segment [%s] to system v key",
0344                 p);
0345         EXFAIL_OUT(ret);
0346     }
0347     
0348     ret = ipckey + pp->idx;
0349     
0350     NDRX_LOG(log_info, "[%s] segment mapped to ipc key %x", path, ret);
0351     
0352 out:
0353     
0354     return ret;
0355 }
0356 
0357 /**
0358  * Remove shared memory segment by name
0359  * @param path shm path
0360  * @return EXSUCCEED/EXFAIL
0361  */
0362 expublic int ndrx_shm_remove_name(char *path, key_t ipckey)
0363 {
0364     int ret = EXSUCCEED;
0365     key_t key = keygetshm(path, ipckey);
0366     int fd;
0367     
0368     if (EXFAIL!=key)
0369     {
0370         /* try to remove the mem.. */
0371         if (EXFAIL!=(fd = shmget(key, 0, S_IRWXU | S_IRWXG)))
0372         {
0373             if (EXSUCCEED!=shmctl(fd, IPC_RMID, NULL))
0374             {
0375                 NDRX_LOG_EARLY(log_error, "Failed to IPC_RMID %d/%x: [%s]: %s",
0376                                 fd, key, path, strerror(errno));
0377                 ret = EXFAIL;
0378             }
0379         }
0380     }
0381     
0382 out:
0383     return ret;
0384 }
0385 
0386 /**
0387  * List shred mem blocks
0388  * @param ipckey IPC key configured for the system
0389  * @return list of segments or NULL if no segments open (or error)
0390  */
0391 expublic string_list_t * ndrx_shm_shms_list(key_t ipckey)
0392 {
0393     string_list_t *ret = NULL;
0394     char segment[NDRX_MAX_Q_SIZE*2];
0395     int i;
0396     key_t key;
0397     int fd;
0398     
0399     for (i=0; NULL!=M_map[i].suffix; i++)
0400     {
0401         key = ipckey + M_map[i].idx;
0402         
0403         if (EXFAIL!=(fd = shmget(key, 0, S_IRWXU | S_IRWXG)))
0404         {
0405             snprintf(segment, sizeof(segment), "%x:%d:%s", 
0406                     (unsigned int)key, fd, M_map[i].suffix);
0407             if (EXSUCCEED!=ndrx_string_list_add(&ret, segment))
0408             {
0409                 NDRX_LOG(log_error, "Failed to add shm segment to list");
0410                 if (NULL!=ret)
0411                 {
0412                     ndrx_string_list_free(ret);
0413                     ret = NULL;
0414                 }
0415                 goto out;
0416             }
0417         }
0418     }
0419 out:
0420     return ret;
0421 }
0422 
0423 /* vim: set ts=4 sw=4 et smartindent: */