lock_ops.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /*
  2. *
  3. * Copyright (C) 2001-2003 FhG Fokus
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. /*!
  18. * \file
  19. * \brief Kamailio core :: Kamailio locking library
  20. * \ingroup core
  21. * \author andrei
  22. * Module: \ref core
  23. *
  24. * WARNING: do not include this file directly, use instead locking.h
  25. * (unless you don't need to alloc/dealloc locks)
  26. *
  27. *
  28. Implements:
  29. simple locks:
  30. -------------
  31. gen_lock_t* lock_init(gen_lock_t* lock); - inits the lock
  32. void lock_destroy(gen_lock_t* lock); - removes the lock (e.g sysv rmid)
  33. void lock_get(gen_lock_t* lock); - lock (mutex down)
  34. void lock_release(gen_lock_t* lock); - unlock (mutex up)
  35. int lock_try(gen_lock_t* lock); - tries to get the lock, returns
  36. 0 on success and !=0 on failure
  37. lock sets:
  38. ----------
  39. gen_lock_set_t* lock_set_init(gen_lock_set_t* set); - inits the lock set
  40. void lock_set_destroy(gen_lock_set_t* s); - removes the lock set
  41. void lock_set_get(gen_lock_set_t* s, int i); - locks sem i from the set
  42. void lock_set_release(gen_lock_set_t* s, int i) - unlocks sem i from the
  43. set
  44. int lock_set_try(gen_lock_set_t* s, int i); - tries to lock the sem i,
  45. returns 0 on success and
  46. !=0 on failure
  47. defines:
  48. --------
  49. GEN_LOCK_T_PREFERRED - defined if using arrays of gen_lock_t is as good as
  50. using a lock set (gen_lock_set_t).
  51. In general is better to have the locks "close" or
  52. inside the protected data structure rather then
  53. having a separate array or lock set. However in some
  54. case (e.g. SYSV_LOCKS) is better to use lock sets,
  55. either due to lock number limitations, excesive
  56. performance or memory overhead. In this cases
  57. GEN_LOCK_T_PREFERRED will not be defined.
  58. GEN_LOCK_T_UNLIMITED - defined if there is no system imposed limit on
  59. the number of locks (other then the memory).
  60. GEN_LOCK_SET_T_UNLIMITED
  61. - like above but for the size of a lock set.
  62. WARNING: - lock_set_init may fail for large number of sems (e.g. sysv).
  63. - signals are not treated! (some locks are "awakened" by the signals)
  64. */
  65. #ifndef _lock_ops_h
  66. #define _lock_ops_h
  67. #ifdef USE_FUTEX
  68. #include "futexlock.h"
  69. /* if no native atomic ops support => USE_FUTEX will be undefined */
  70. #endif
  71. #ifdef USE_FUTEX
  72. typedef futex_lock_t gen_lock_t;
  73. #define lock_destroy(lock) /* do nothing */
  74. #define lock_init(lock) futex_init(lock)
  75. #define lock_try(lock) futex_try(lock)
  76. #define lock_get(lock) futex_get(lock)
  77. #define lock_release(lock) futex_release(lock)
  78. #elif defined FAST_LOCK
  79. #include "fastlock.h"
  80. typedef fl_lock_t gen_lock_t;
  81. #define lock_destroy(lock) /* do nothing */
  82. inline static gen_lock_t* lock_init(gen_lock_t* lock)
  83. {
  84. init_lock(*lock);
  85. return lock;
  86. }
  87. #define lock_try(lock) try_lock(lock)
  88. #define lock_get(lock) get_lock(lock)
  89. #define lock_release(lock) release_lock(lock)
  90. #elif defined USE_PTHREAD_MUTEX
  91. #include <pthread.h>
  92. typedef pthread_mutex_t gen_lock_t;
  93. #define lock_destroy(lock) /* do nothing */
  94. inline static gen_lock_t* lock_init(gen_lock_t* lock)
  95. {
  96. if (pthread_mutex_init(lock, 0)==0) return lock;
  97. else return 0;
  98. }
  99. #define lock_try(lock) pthread_mutex_trylock(lock)
  100. #define lock_get(lock) pthread_mutex_lock(lock)
  101. #define lock_release(lock) pthread_mutex_unlock(lock)
  102. #elif defined USE_POSIX_SEM
  103. #include <semaphore.h>
  104. typedef sem_t gen_lock_t;
  105. #define lock_destroy(lock) /* do nothing */
  106. inline static gen_lock_t* lock_init(gen_lock_t* lock)
  107. {
  108. if (sem_init(lock, 1, 1)<0) return 0;
  109. return lock;
  110. }
  111. #define lock_try(lock) sem_trywait(lock)
  112. #define lock_get(lock) sem_wait(lock)
  113. #define lock_release(lock) sem_post(lock)
  114. #elif defined USE_SYSV_SEM
  115. #include <sys/ipc.h>
  116. #include <sys/sem.h>
  117. #include <errno.h>
  118. #include <string.h>
  119. #include <sys/types.h>
  120. #include <unistd.h>
  121. #include "dprint.h"
  122. #include "globals.h" /* uid */
  123. #if ((defined(HAVE_UNION_SEMUN) || defined(__GNU_LIBRARY__) )&& !defined(_SEM_SEMUN_UNDEFINED))
  124. /* union semun is defined by including sem.h */
  125. #else
  126. /* according to X/OPEN we have to define it ourselves */
  127. union semun {
  128. int val; /* value for SETVAL */
  129. struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
  130. unsigned short int *array; /* array for GETALL, SETALL */
  131. struct seminfo *__buf; /* buffer for IPC_INFO */
  132. };
  133. #endif
  134. typedef int gen_lock_t;
  135. inline static gen_lock_t* lock_init(gen_lock_t* lock)
  136. {
  137. union semun su;
  138. int euid;
  139. euid=geteuid();
  140. if (uid && uid!=euid)
  141. seteuid(uid); /* set euid to the cfg. requested one */
  142. *lock=semget(IPC_PRIVATE, 1, 0700);
  143. if (uid && uid!=euid)
  144. seteuid(euid); /* restore it */
  145. if (*lock==-1) return 0;
  146. su.val=1;
  147. if (semctl(*lock, 0, SETVAL, su)==-1){
  148. /* init error*/
  149. return 0;
  150. }
  151. return lock;
  152. }
  153. inline static void lock_destroy(gen_lock_t* lock)
  154. {
  155. semctl(*lock, 0, IPC_RMID, (union semun)(int)0);
  156. }
  157. /* returns 0 if it got the lock, -1 otherwise */
  158. inline static int lock_try(gen_lock_t* lock)
  159. {
  160. struct sembuf sop;
  161. sop.sem_num=0;
  162. sop.sem_op=-1; /* down */
  163. sop.sem_flg=IPC_NOWAIT;
  164. tryagain:
  165. if (semop(*lock, &sop, 1)==-1){
  166. if (errno==EAGAIN){
  167. return -1;
  168. }else if (errno==EINTR){
  169. DBG("lock_get: signal received while waiting for on a mutex\n");
  170. goto tryagain;
  171. }else{
  172. LM_CRIT("sysv: %s (%d)\n", strerror(errno), errno);
  173. return -1;
  174. }
  175. }
  176. return 0;
  177. }
  178. inline static void lock_get(gen_lock_t* lock)
  179. {
  180. struct sembuf sop;
  181. sop.sem_num=0;
  182. sop.sem_op=-1; /* down */
  183. sop.sem_flg=0;
  184. tryagain:
  185. if (semop(*lock, &sop, 1)==-1){
  186. if (errno==EINTR){
  187. DBG("lock_get: signal received while waiting for on a mutex\n");
  188. goto tryagain;
  189. }else{
  190. LM_CRIT("sysv: %s (%d)\n", strerror(errno), errno);
  191. }
  192. }
  193. }
  194. inline static void lock_release(gen_lock_t* lock)
  195. {
  196. struct sembuf sop;
  197. sop.sem_num=0;
  198. sop.sem_op=1; /* up */
  199. sop.sem_flg=0;
  200. tryagain:
  201. if (semop(*lock, &sop, 1)==-1){
  202. if (errno==EINTR){
  203. /* very improbable*/
  204. DBG("lock_release: signal received while releasing a mutex\n");
  205. goto tryagain;
  206. }else{
  207. LM_CRIT("sysv: %s (%d)\n", strerror(errno), errno);
  208. }
  209. }
  210. }
  211. #else
  212. #error "no locking method selected"
  213. #endif
  214. /* lock sets */
  215. #if defined(FAST_LOCK) || defined(USE_PTHREAD_MUTEX) || \
  216. defined(USE_POSIX_SEM) || defined(USE_FUTEX)
  217. #define GEN_LOCK_T_PREFERRED
  218. #define GEN_LOCK_T_PREFERED /* backwards compat. */
  219. #define GEN_LOCK_T_UNLIMITED
  220. #define GEN_LOCK_SET_T_UNLIMITED
  221. struct gen_lock_set_t_ {
  222. long size;
  223. gen_lock_t* locks;
  224. }; /* must be aligned (32 bits or 64 depending on the arch)*/
  225. typedef struct gen_lock_set_t_ gen_lock_set_t;
  226. #define lock_set_destroy(lock_set) /* do nothing */
  227. inline static gen_lock_set_t* lock_set_init(gen_lock_set_t* s)
  228. {
  229. int r;
  230. for (r=0; r<s->size; r++) if (lock_init(&s->locks[r])==0) return 0;
  231. return s;
  232. }
  233. /* WARNING: no boundary checks!*/
  234. #define lock_set_try(set, i) lock_try(&set->locks[i])
  235. #define lock_set_get(set, i) lock_get(&set->locks[i])
  236. #define lock_set_release(set, i) lock_release(&set->locks[i])
  237. #elif defined(USE_SYSV_SEM)
  238. #undef GEN_LOCK_T_PREFERRED
  239. #undef GEN_LOCK_T_PREFERED /* backwards compat. */
  240. #undef GEN_LOCK_T_UNLIMITED
  241. #undef GEN_LOCK_SET_T_UNLIMITED
  242. #define GEN_LOCK_T_LIMITED
  243. #define GEN_LOCK_SET_T_LIMITED
  244. struct gen_lock_set_t_ {
  245. int size;
  246. int semid;
  247. };
  248. typedef struct gen_lock_set_t_ gen_lock_set_t;
  249. inline static gen_lock_set_t* lock_set_init(gen_lock_set_t* s)
  250. {
  251. union semun su;
  252. int r;
  253. int euid;
  254. euid=geteuid();
  255. if (uid && uid!=euid)
  256. seteuid(uid); /* set euid to the cfg. requested one */
  257. s->semid=semget(IPC_PRIVATE, s->size, 0700);
  258. if (uid && uid!=euid)
  259. seteuid(euid); /* restore euid */
  260. if (s->semid==-1){
  261. LM_CRIT("(SYSV): semget (..., %d, 0700) failed: %s\n",
  262. s->size, strerror(errno));
  263. return 0;
  264. }
  265. su.val=1;
  266. for (r=0; r<s->size; r++){
  267. if (semctl(s->semid, r, SETVAL, su)==-1){
  268. LM_CRIT("(SYSV): semctl failed on sem %d: %s\n", r, strerror(errno));
  269. semctl(s->semid, 0, IPC_RMID, (union semun)(int)0);
  270. return 0;
  271. }
  272. }
  273. return s;
  274. }
  275. inline static void lock_set_destroy(gen_lock_set_t* s)
  276. {
  277. semctl(s->semid, 0, IPC_RMID, (union semun)(int)0);
  278. }
  279. /* returns 0 if it "gets" the lock, -1 otherwise */
  280. inline static int lock_set_try(gen_lock_set_t* s, int n)
  281. {
  282. struct sembuf sop;
  283. sop.sem_num=n;
  284. sop.sem_op=-1; /* down */
  285. sop.sem_flg=IPC_NOWAIT;
  286. tryagain:
  287. if (semop(s->semid, &sop, 1)==-1){
  288. if (errno==EAGAIN){
  289. return -1;
  290. }else if (errno==EINTR){
  291. DBG("lock_get: signal received while waiting for on a mutex\n");
  292. goto tryagain;
  293. }else{
  294. LM_CRIT("sysv: %s (%d)\n", strerror(errno), errno);
  295. return -1;
  296. }
  297. }
  298. return 0;
  299. }
  300. inline static void lock_set_get(gen_lock_set_t* s, int n)
  301. {
  302. struct sembuf sop;
  303. sop.sem_num=n;
  304. sop.sem_op=-1; /* down */
  305. sop.sem_flg=0;
  306. tryagain:
  307. if (semop(s->semid, &sop, 1)==-1){
  308. if (errno==EINTR){
  309. DBG("lock_set_get: signal received while waiting on a mutex\n");
  310. goto tryagain;
  311. }else{
  312. LM_CRIT("sysv: %s (%d)\n", strerror(errno), errno);
  313. }
  314. }
  315. }
  316. inline static void lock_set_release(gen_lock_set_t* s, int n)
  317. {
  318. struct sembuf sop;
  319. sop.sem_num=n;
  320. sop.sem_op=1; /* up */
  321. sop.sem_flg=0;
  322. tryagain:
  323. if (semop(s->semid, &sop, 1)==-1){
  324. if (errno==EINTR){
  325. /* very improbable */
  326. DBG("lock_set_release: signal received while releasing mutex\n");
  327. goto tryagain;
  328. }else{
  329. LM_CRIT("sysv: %s (%d)\n", strerror(errno), errno);
  330. }
  331. }
  332. }
  333. #else
  334. #error "no lock set method selected"
  335. #endif
  336. #endif