Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Enduro/X Standard Libary Semaphore commons
0003  *
0004  * @file nstd_sem.c
0005  */
0006 /* -----------------------------------------------------------------------------
0007  * Enduro/X Middleware Platform for Distributed Transaction Processing
0008  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0009  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0010  * This software is released under one of the following licenses:
0011  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0012  * See LICENSE file for full text.
0013  * -----------------------------------------------------------------------------
0014  * AGPL license:
0015  *
0016  * This program is free software; you can redistribute it and/or modify it under
0017  * the terms of the GNU Affero General Public License, version 3 as published
0018  * by the Free Software Foundation;
0019  *
0020  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0021  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0022  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0023  * for more details.
0024  *
0025  * You should have received a copy of the GNU Affero General Public License along 
0026  * with this program; if not, write to the Free Software Foundation, Inc.,
0027  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0028  *
0029  * -----------------------------------------------------------------------------
0030  * A commercial use license is available from Mavimax, Ltd
0031  * contact@mavimax.com
0032  * -----------------------------------------------------------------------------
0033  */
0034 
0035 /*---------------------------Includes-----------------------------------*/
0036 
0037 #include <stdlib.h>
0038 #include <stdio.h>
0039 
0040 /* shm_* stuff, and mmap() */
0041 #include <sys/mman.h>
0042 #include <sys/types.h>
0043 #include <sys/sem.h>
0044 /* exit() etc */
0045 #include <unistd.h>
0046 #include <fcntl.h>
0047 #include <sys/stat.h>
0048 
0049 #include <ndrstandard.h>
0050 #include <ndebug.h>
0051 #include <nstd_shm.h>
0052 
0053 
0054 /*---------------------------Externs------------------------------------*/
0055 /*---------------------------Macros-------------------------------------*/
0056 /*---------------------------Enums--------------------------------------*/
0057 /*---------------------------Typedefs-----------------------------------*/
0058 /*---------------------------Globals------------------------------------*/
0059 /*---------------------------Statics------------------------------------*/
0060 /*---------------------------Prototypes---------------------------------*/
0061 
0062 /**
0063  * Perform RW lock
0064  * @param sem semaphore def
0065  * @param sem_num semaphore number / primitive
0066  * @param typ see NDRX_SEM_OP_WRITE or NDRX_SEM_OP_READ
0067  * @return EXFAIL in case of failure
0068  */
0069 expublic int ndrx_sem_rwlock(ndrx_sem_t *sem, int sem_num, int typ)
0070 {
0071     int ret;
0072     struct sembuf semops;
0073     semops.sem_num = sem_num;
0074     semops.sem_flg = SEM_UNDO;
0075 
0076     if( typ == NDRX_SEM_TYP_WRITE ) 
0077     {
0078         semops.sem_op = -sem->maxreaders;  
0079     }
0080     else 
0081     {
0082         semops.sem_op = -1;
0083     }
0084     
0085     do 
0086     {
0087         ret = semop( sem->semid, &semops, 1 );
0088 
0089     } while ( ret == -1 && errno == EINTR );
0090 
0091     if (EXFAIL==ret)
0092     {
0093         int err = errno;
0094         
0095         /* use buffered log as my conflict with LCF */
0096         userlog("ndrx_sem_rwlock: semop() failed for type %d lock: %s", 
0097                 typ, strerror(err));
0098     }
0099 
0100     return ret;
0101 }
0102 
0103 /**
0104  * Read / Write locks - unlock
0105  * @param sem semaphore def
0106  * @param sem_num semaphore number / primitive
0107  * @param typ see NDRX_SEM_OP_WRITE or NDRX_SEM_OP_READ
0108  * @return EXSUCCEED/EXFAIL
0109  */
0110 expublic int ndrx_sem_rwunlock(ndrx_sem_t *sem, int sem_num, int typ)
0111 {
0112     int ret;
0113     struct sembuf semops;
0114     semops.sem_num = sem_num;
0115     semops.sem_op = 1;
0116     semops.sem_flg = SEM_UNDO;
0117 
0118     if ( typ == NDRX_SEM_TYP_WRITE )
0119     {
0120         semops.sem_op = sem->maxreaders;
0121     }
0122 
0123     do 
0124     {
0125         ret = semop(sem->semid,&semops,1);
0126 
0127     } while ( ret == -1 && errno == EINTR );
0128     
0129     if (EXFAIL==ret)
0130     {
0131         int err = errno;
0132         
0133         userlog("ndrx_sem_rwunlock: semop() failed for %d type lock: %s", 
0134                 typ, strerror(err));
0135     }
0136     
0137     return ret;
0138 }
0139 
0140 /**
0141  * Generic sem lock
0142  * @param sem
0143  * @param msg
0144  * @return 
0145  */
0146 expublic int ndrx_sem_lock(ndrx_sem_t *sem, const char *msg, int sem_num)
0147 {
0148     int ret=EXSUCCEED;
0149     int errno_int;
0150     struct sembuf semops;
0151     semops.sem_num = sem_num;
0152     semops.sem_flg = SEM_UNDO;
0153     
0154     /* lock all */
0155     semops.sem_op = -sem->maxreaders;  
0156     
0157 #ifdef NDRX_SEM_DEBUG
0158     userlog("ENTER: ndrx_lock: %s", msg);
0159 #endif
0160     
0161     while(EXFAIL==(ret=semop(sem->semid, &semops, 1)) && (EINTR==errno || EAGAIN==errno))
0162     {
0163         NDRX_LOG(log_warn, "%s: Interrupted while waiting for semaphore!!", msg);
0164     };
0165     errno_int = errno;
0166     
0167     if (EXSUCCEED==ret)
0168     {
0169         NDRX_LOG(log_info, "%s/%d/%d: semaphore locked... ", msg, sem->semid, sem_num);
0170     }
0171     else
0172     {
0173         NDRX_LOG(log_info, "%s/%d/%d: failed to lock (%d): %s", msg, sem->semid, 
0174                 sem_num, errno_int,
0175                 strerror(errno_int));
0176     }
0177     
0178 #ifdef NDRX_SEM_DEBUG
0179     userlog("EXIT: ndrx_lock %d: %s", ret, msg);
0180 #endif
0181     
0182     return ret;
0183 }
0184 
0185 /**
0186  * Generic sem unlock
0187  * @param sem
0188  * @param msg
0189  * @return 
0190  */
0191 expublic int ndrx_sem_unlock(ndrx_sem_t *sem, const   char *msg, int sem_num)
0192 {
0193     struct sembuf semops;
0194     semops.sem_num = sem_num;
0195     semops.sem_flg = SEM_UNDO;
0196     
0197     semops.sem_op = sem->maxreaders;  
0198 
0199 #ifdef NDRX_SEM_DEBUG
0200     userlog("ENTER: ndrx_unlock: %s", msg);
0201 #endif
0202     
0203     if (EXSUCCEED!=semop(sem->semid, &semops, 1))
0204     {
0205         NDRX_LOG(log_debug, "%s/%d%/d: failed: %s", msg, 
0206                 sem->semid, sem_num, strerror(errno));
0207         return EXFAIL;
0208     }
0209     
0210     NDRX_LOG(log_debug, "%s/%d/%d semaphore un-locked", 
0211             msg, sem->semid, sem_num);
0212     
0213 #ifdef NDRX_SEM_DEBUG
0214     userlog("EXIT: ndrx_unlock: %s", msg);
0215 #endif
0216     
0217     return EXSUCCEED;
0218 }
0219 
0220 /**
0221  * Open service info semaphore segment
0222  * @param sem initialized semaphore block
0223  * @param attach_on_exists if not EXFALSE, attach to sem if exists
0224  * @return EXSUCCEED/EXFAIL
0225  */
0226 expublic int ndrx_sem_open(ndrx_sem_t *sem, int attach_on_exists)
0227 {
0228     int ret=EXSUCCEED;
0229     int err, i;
0230 
0231 #ifdef EX_HAVE_SEMUN
0232     union semun arg;
0233 #else
0234     union semun 
0235     {
0236         int val;
0237         struct semid_ds *buf;
0238         ushort *array;
0239     } arg;
0240 #endif
0241     
0242     ushort arr[sem->nrsems];
0243     memset(&arg, 0, sizeof(arg));
0244 
0245     /* for setting initial value... */
0246     arg.array = arr;
0247     
0248     /* creating the semaphore object --  sem_open() 
0249      * this will attach anyway?
0250      */
0251     sem->semid = semget(sem->key, sem->nrsems, 0660|IPC_CREAT|IPC_EXCL);
0252 
0253     if (EXFAIL==sem->semid) 
0254     {
0255         err = errno;
0256         
0257         if (EEXIST==err && attach_on_exists)
0258         {
0259             NDRX_LOG_EARLY(log_info, "Semaphore exists [%x] - attaching",
0260                     sem->key);
0261             return ndrx_sem_attach(sem);
0262         }
0263         
0264         NDRX_LOG_EARLY(log_error, "Failed to create sem, key[%x]: %s",
0265                             sem->key, strerror(err));
0266         ret=EXFAIL;
0267         goto out;
0268     }
0269    
0270     /* Reset semaphore... */
0271     for (i=0; i< sem->nrsems; i++)
0272     {
0273         arg.array[i]=sem->maxreaders;
0274     }
0275     
0276     if (semctl(sem->semid, i, SETALL, arg) == -1) 
0277     {
0278         NDRX_LOG_EARLY(log_error, "Failed to reset to %d, key[%x], semid: %d: %s",
0279                             i, sem->key, sem->semid, strerror(errno));
0280         ret=EXFAIL;
0281         goto out;
0282     }
0283     
0284     sem->attached = EXTRUE;
0285     
0286     NDRX_LOG_EARLY(log_warn, "Semaphore for key %x open, id: %d", 
0287             sem->key, sem->semid);
0288 out:
0289 
0290     NDRX_LOG_EARLY(log_debug, "return %d", ret);
0291 
0292     return ret;
0293 }
0294 
0295 
0296 /**
0297  * Remove semaphores...
0298  * @param sem
0299  * @return EXSUCCEED/EXFAIL
0300  */
0301 expublic int ndrx_sem_remove(ndrx_sem_t *sem, int force)
0302 {
0303     int ret = EXSUCCEED;
0304     /* Close that one... */
0305     if ((sem->attached || force) && sem->semid)
0306     {
0307         NDRX_LOG_EARLY(log_error, "Removing semid: %d", sem->semid);
0308         if (EXSUCCEED!= semctl(sem->semid, 0, IPC_RMID))
0309         {
0310             NDRX_LOG_EARLY(log_warn, "semctl DEL failed err: %s", 
0311                     strerror(errno));
0312             ret=EXFAIL;
0313         }
0314         else
0315         {
0316             sem->semid=0;
0317         }
0318     }
0319     sem->attached=EXFALSE;
0320     
0321     return ret;
0322 }
0323 
0324 /**
0325  * Returns true if currently attached to sem
0326  * WARNING: This assumes that fd 0 could never be used by sem!
0327  * @return TRUE/FALSE
0328  */
0329 expublic int ndrx_sem_is_attached(ndrx_sem_t *sem)
0330 {
0331     int ret=EXTRUE;
0332     
0333     if (!sem->attached)
0334     {
0335         ret=EXFALSE;
0336     }
0337 
0338     return ret;
0339 }
0340 
0341 /**
0342  * Attach to semaphore, semaphore must exist!
0343  * @return EXSUCCEED/EXFAIL
0344  */
0345 expublic int ndrx_sem_attach(ndrx_sem_t *sem)
0346 {
0347     int ret=EXSUCCEED;
0348 
0349     NDRX_LOG_EARLY(log_debug, "enter");
0350     
0351     if (sem->attached)
0352     {
0353         NDRX_LOG_EARLY(log_debug, "sem, key %x, id: %d already attached", 
0354                 sem->key, sem->semid);
0355         goto out;
0356     }
0357     
0358     /* Attach to semaphore block */
0359     sem->semid = semget(sem->key, sem->nrsems, IPC_EXCL);
0360 
0361     if (EXFAIL==sem->semid) 
0362     {
0363         NDRX_LOG_EARLY(log_error, "Failed to attach sem, key [%d]: %s",
0364                             sem->key, strerror(errno));
0365         ret=EXFAIL;
0366         goto out;
0367     }
0368 
0369     NDRX_LOG_EARLY(log_debug, "sem: [%d] attached", sem->semid);
0370 
0371 out:
0372 
0373     NDRX_LOG_EARLY(log_debug, "return %d", ret);
0374     return ret;
0375 }
0376 
0377 /**
0378  * Close opened semaphore segment.
0379  * ??? Not sure shall we close it ?
0380  * For System V not needed.
0381  * @return EXSUCCEED
0382  */
0383 expublic int ndrx_sem_close(ndrx_sem_t *sem)
0384 {
0385     int ret=EXSUCCEED;
0386 
0387 out:
0388     return ret;
0389 }
0390 
0391 
0392 /* vim: set ts=4 sw=4 et smartindent: */