nslock.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. * END COPYRIGHT BLOCK **/
  6. /*
  7. * Description (nslock.c)
  8. *
  9. * This modules provides an interprocess locking mechanism, based
  10. * on a named lock.
  11. */
  12. #include "netsite.h"
  13. #include "base/file.h"
  14. #define __PRIVATE_NSLOCK
  15. #include "nslock.h"
  16. #include <assert.h>
  17. char * NSLock_Program = "NSLOCK";
  18. #ifdef FILE_UNIX
  19. /*
  20. * The process-wide list of locks, NSLock_List, is protected by the
  21. * critical section, NSLock_Crit.
  22. */
  23. CRITICAL NSLock_Crit = 0;
  24. NSLock_t * NSLock_List = 0;
  25. #endif /* FILE_UNIX */
  26. /*
  27. * Description (nsLockOpen)
  28. *
  29. * This function is used to initialize a handle for a lock. The
  30. * caller specifies a unique name for the lock, and a handle is
  31. * returned. The returned handle should be used by only one
  32. * thread at a time, i.e. if multiple threads in a process are
  33. * using the same lock, they should either have their own handles
  34. * or protect a single handle with a critical section.
  35. *
  36. * Arguments:
  37. *
  38. * errp - error frame list pointer (may be null)
  39. * lockname - pointer to name of lock
  40. * plock - pointer to returned handle for lock
  41. *
  42. * Returns:
  43. *
  44. * If successful, a handle for the specified lock is returned via
  45. * 'plock', and the return value is zero. Otherwise the return
  46. * value is a negative error code (see nslock.h), and an error
  47. * frame is generated if an error frame list was provided.
  48. */
  49. NSAPI_PUBLIC int nsLockOpen(NSErr_t * errp, char * lockname, void **plock)
  50. {
  51. NSLock_t * nl = 0; /* pointer to lock structure */
  52. int len; /* length of lockname */
  53. int eid;
  54. int rv;
  55. #ifdef FILE_UNIX
  56. /* Have we created the critical section for NSLock_List yet? */
  57. if (NSLock_Crit == 0) {
  58. /* Narrow the window for simultaneous initialization */
  59. NSLock_Crit = (CRITICAL)(-1);
  60. /* Create it */
  61. NSLock_Crit = crit_init();
  62. }
  63. /* Lock the list of locks */
  64. crit_enter(NSLock_Crit);
  65. /* See if a lock with the specified name exists already */
  66. for (nl = NSLock_List; nl != 0; nl = nl->nl_next) {
  67. if (!strcmp(nl->nl_name, lockname)) break;
  68. }
  69. /* Create a new lock if we didn't find it */
  70. if (nl == 0) {
  71. len = strlen(lockname);
  72. nl = (NSLock_t *)PERM_MALLOC(sizeof(NSLock_t) + len + 5);
  73. if (nl == 0) goto err_nomem;
  74. nl->nl_name = (char *)(nl + 1);
  75. strcpy(nl->nl_name, lockname);
  76. strcpy(&nl->nl_name[len], ".lck");
  77. nl->nl_cnt = 0;
  78. nl->nl_fd = open(nl->nl_name, O_RDWR|O_CREAT|O_EXCL, 0644);
  79. if (nl->nl_fd < 0) {
  80. if (errno != EEXIST) {
  81. crit_exit(NSLock_Crit);
  82. goto err_create;
  83. }
  84. /* O_RDWR or O_WRONLY is required to use lockf on Solaris */
  85. nl->nl_fd = open(nl->nl_name, O_RDWR, 0);
  86. if (nl->nl_fd < 0) {
  87. crit_exit(NSLock_Crit);
  88. goto err_open;
  89. }
  90. }
  91. /* Remove ".lck" from the lock name */
  92. nl->nl_name[len] = 0;
  93. /* Create a critical section for this lock (gag!) */
  94. nl->nl_crit = crit_init();
  95. /* Add this lock to NSLock_List */
  96. nl->nl_next = NSLock_List;
  97. NSLock_List = nl;
  98. }
  99. crit_exit(NSLock_Crit);
  100. #else
  101. /* write me */
  102. nl = (void *)4;
  103. #endif /* FILE_UNIX */
  104. *plock = (void *)nl;
  105. return 0;
  106. err_nomem:
  107. eid = NSLERR1000;
  108. rv = NSLERRNOMEM;
  109. nserrGenerate(errp, rv, eid, NSLock_Program, 0);
  110. goto punt;
  111. err_create:
  112. eid = NSLERR1020;
  113. rv = NSLERRCREATE;
  114. goto err_file;
  115. err_open:
  116. eid = NSLERR1040;
  117. rv = NSLERROPEN;
  118. err_file:
  119. nserrGenerate(errp, rv, eid, NSLock_Program, 1, nl->nl_name);
  120. punt:
  121. if (nl) {
  122. FREE(nl);
  123. }
  124. *plock = 0;
  125. return rv;
  126. }
  127. /*
  128. * Description (nsLockAcquire)
  129. *
  130. * This function is used to acquire exclusive ownership of a lock
  131. * previously accessed via nsLockOpen(). The calling thread will
  132. * be blocked until the lock is acquired. Other threads in the
  133. * process should not be blocked.
  134. *
  135. * Arguments:
  136. *
  137. * errp - error frame list pointer (may be null)
  138. * lock - handle for lock from nsLockOpen()
  139. *
  140. * Returns:
  141. *
  142. * If successful, the return value is zero. Otherwise the return
  143. * value is a negative error code (see nslock.h), and an error
  144. * frame is generated if an error frame list was provided.
  145. */
  146. NSAPI_PUBLIC int nsLockAcquire(NSErr_t * errp, void * lock)
  147. {
  148. NSLock_t * nl = (NSLock_t *)lock;
  149. int eid;
  150. int rv;
  151. #ifdef FILE_UNIX
  152. /* Enter the critical section for the lock */
  153. crit_enter(nl->nl_crit);
  154. /* Acquire the file lock if we haven't already */
  155. if (nl->nl_cnt == 0) {
  156. rv = system_flock(nl->nl_fd);
  157. if (rv) {
  158. crit_exit(nl->nl_crit);
  159. goto err_lock;
  160. }
  161. }
  162. /* Bump the lock count */
  163. nl->nl_cnt++;
  164. crit_exit(nl->nl_crit);
  165. #else
  166. /* write me */
  167. #endif /* FILE_UNIX */
  168. /* Indicate success */
  169. return 0;
  170. err_lock:
  171. eid = NSLERR1100;
  172. rv = NSLERRLOCK;
  173. nserrGenerate(errp, rv, eid, NSLock_Program, 1, nl->nl_name);
  174. return rv;
  175. }
  176. /*
  177. * Description (nsLockRelease)
  178. *
  179. * This function is used to release exclusive ownership to a lock
  180. * that was previously obtained via nsLockAcquire().
  181. *
  182. * Arguments:
  183. *
  184. * lock - handle for lock from nsLockOpen()
  185. */
  186. NSAPI_PUBLIC void nsLockRelease(void * lock)
  187. {
  188. NSLock_t * nl = (NSLock_t *)lock;
  189. #ifdef FILE_UNIX
  190. assert(nl->nl_cnt > 0);
  191. crit_enter(nl->nl_crit);
  192. if (--nl->nl_cnt <= 0) {
  193. system_ulock(nl->nl_fd);
  194. nl->nl_cnt = 0;
  195. }
  196. crit_exit(nl->nl_crit);
  197. #endif /* FILE_UNIX */
  198. }
  199. /*
  200. * Description (nsLockClose)
  201. *
  202. * This function is used to close a lock handle that was previously
  203. * acquired via nsLockOpen(). The lock should not be owned.
  204. *
  205. * Arguments:
  206. *
  207. * lock - handle for lock from nsLockOpen()
  208. */
  209. NSAPI_PUBLIC void nsLockClose(void * lock)
  210. {
  211. NSLock_t * nl = (NSLock_t *)lock;
  212. #ifdef FILE_UNIX
  213. /* Don't do anything with the lock, since it will get used again */
  214. #if 0
  215. crit_enter(nl->nl_crit);
  216. close(nl->nl_fd);
  217. crit_exit(nl->nl_crit);
  218. FREE(nl);
  219. #endif
  220. #else
  221. /* write me */
  222. #endif FILE_UNIX
  223. }