shmget.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. /****************************************************************************
  2. * mm/shm/shmget.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ****************************************************************************/
  20. /****************************************************************************
  21. * Included Files
  22. ****************************************************************************/
  23. #include <nuttx/config.h>
  24. #include <sys/shm.h>
  25. #include <sys/ipc.h>
  26. #include <unistd.h>
  27. #include <string.h>
  28. #include <errno.h>
  29. #include <nuttx/pgalloc.h>
  30. #include <nuttx/mm/shm.h>
  31. #include "shm/shm.h"
  32. #ifdef CONFIG_MM_SHM
  33. /****************************************************************************
  34. * Private Functions
  35. ****************************************************************************/
  36. /****************************************************************************
  37. * Name: shm_find
  38. *
  39. * Description:
  40. * Find the shared memory region with matching key
  41. *
  42. * Input Parameters:
  43. * key - The value that uniquely identifies a shared memory region.
  44. *
  45. * Returned Value:
  46. * On success, an index in the range of 0 to CONFIG_ARCH_SHM_MAXREGIONS-1
  47. * is returned to identify the matching region; -ENOENT is returned on
  48. * failure.
  49. *
  50. ****************************************************************************/
  51. static int shm_find(key_t key)
  52. {
  53. int i;
  54. for (i = 0; i < CONFIG_ARCH_SHM_MAXREGIONS; i++)
  55. {
  56. if (g_shminfo.si_region[i].sr_key == key)
  57. {
  58. return i;
  59. }
  60. }
  61. return -ENOENT;
  62. }
  63. /****************************************************************************
  64. * Name: shm_reserve
  65. *
  66. * Description:
  67. * Allocate an unused shared memory region. That is one with a key of -1
  68. *
  69. * Input Parameters:
  70. * None
  71. *
  72. * Returned Value:
  73. * On success, an index in the range of 0 to CONFIG_ARCH_SHM_MAXREGIONS-1
  74. * is returned to identify the matching region; -ENOSPC is returned on
  75. * failure.
  76. *
  77. ****************************************************************************/
  78. static int shm_reserve(key_t key, int shmflg)
  79. {
  80. FAR struct shm_region_s *region;
  81. int i;
  82. for (i = 0; i < CONFIG_ARCH_SHM_MAXREGIONS; i++)
  83. {
  84. /* Is this region in use? */
  85. region = &g_shminfo.si_region[i];
  86. if (region->sr_flags == SRFLAG_AVAILABLE)
  87. {
  88. /* No... reserve it for the caller now */
  89. memset(region, 0, sizeof(struct shm_region_s));
  90. region->sr_key = key;
  91. region->sr_flags = SRFLAG_INUSE;
  92. nxsem_init(&region->sr_sem, 0, 1);
  93. /* Set the low-order nine bits of shm_perm.mode to the low-order
  94. * nine bits of shmflg.
  95. */
  96. region->sr_ds.shm_perm.mode = shmflg & IPC_MODE;
  97. /* The value of shm_segsz is left equal to zero for now because no
  98. * memory has yet been allocated.
  99. *
  100. * The values of shm_lpid, shm_nattch, shm_atime, and shm_dtime are
  101. * set equal to 0.
  102. */
  103. /* The value of shm_ctime is set equal to the current time. */
  104. region->sr_ds.shm_ctime = time(NULL);
  105. return i;
  106. }
  107. }
  108. return -ENOSPC;
  109. }
  110. /****************************************************************************
  111. * Name: shm_extend
  112. *
  113. * Description:
  114. * Extend the size of a memory regions by allocating physical pages as
  115. * necessary
  116. *
  117. * Input Parameters:
  118. * shmid - The index of the region of interest in the shared memory region
  119. * table.
  120. * size - The new size of the region.
  121. *
  122. * Returned Value:
  123. * Zero is returned on success; -ENOMEM is returned on failure.
  124. * (Should a different error be returned if the region is just too big?)
  125. *
  126. ****************************************************************************/
  127. static int shm_extend(int shmid, size_t size)
  128. {
  129. FAR struct shm_region_s *region = &g_shminfo.si_region[shmid];
  130. unsigned int pgalloc;
  131. unsigned int pgneeded;
  132. /* This is the number of pages that are needed to satisfy the allocation */
  133. pgneeded = MM_NPAGES(size);
  134. /* This is the number of pages that have already been allocated */
  135. pgalloc = MM_NPAGES(region->sr_ds.shm_segsz);
  136. /* Loop until all pages have been allocated (or something bad happens) */
  137. while (pgalloc < pgneeded && pgalloc < CONFIG_ARCH_SHM_NPAGES)
  138. {
  139. /* Allocate one more physical page */
  140. region->sr_pages[pgalloc] = mm_pgalloc(1);
  141. if (region->sr_pages[pgalloc] == 0)
  142. {
  143. shmerr("ERROR: mm_pgalloc(1) failed\n");
  144. break;
  145. }
  146. /* Increment the number of pages successfully allocated */
  147. pgalloc++;
  148. }
  149. /* We get here (1) because all of the pages were successfully, (2) because
  150. * mm_pgalloc() failed, or (3) because any additional pages allocated
  151. * would exceed CONFIG_ARCH_SHM_NPAGES.
  152. */
  153. if (pgalloc < pgneeded)
  154. {
  155. /* Set the amount memory available which will be less than the
  156. * requested size.
  157. */
  158. region->sr_ds.shm_segsz = pgalloc << MM_PGSHIFT;
  159. return -ENOMEM;
  160. }
  161. /* Set the new region size and return success */
  162. region->sr_ds.shm_segsz = size;
  163. return OK;
  164. }
  165. /****************************************************************************
  166. * Name: shm_create
  167. *
  168. * Description:
  169. * Create the shared memory region.
  170. *
  171. * Input Parameters:
  172. * key - The key that is used to access the unique shared memory
  173. * identifier.
  174. * size - The shared memory region that is created will be at least
  175. * this size in bytes.
  176. * shmflgs - See IPC_* definitions in sys/ipc.h. Only the values
  177. * IPC_PRIVATE or IPC_CREAT are supported.
  178. *
  179. * Returned Value:
  180. * Zero is returned on success; A negated errno value is returned on
  181. * failure.
  182. *
  183. ****************************************************************************/
  184. static int shm_create(key_t key, size_t size, int shmflg)
  185. {
  186. FAR struct shm_region_s *region;
  187. int shmid;
  188. int ret;
  189. /* Reserve the shared memory region */
  190. ret = shm_reserve(key, shmflg);
  191. if (ret < 0)
  192. {
  193. shmerr("ERROR: shm_reserve failed: %d\n", ret);
  194. return ret;
  195. }
  196. /* Save the shared memory ID */
  197. shmid = ret;
  198. /* Then allocate the physical memory (by extending it from the initial
  199. * size of zero).
  200. */
  201. ret = shm_extend(shmid, size);
  202. if (ret < 0)
  203. {
  204. /* Free any partial allocations and unreserve the region */
  205. shm_destroy(shmid);
  206. return ret;
  207. }
  208. /* Save the process ID of the creator */
  209. region = &g_shminfo.si_region[shmid];
  210. region->sr_ds.shm_cpid = getpid();
  211. /* Return the shared memory ID */
  212. return shmid;
  213. }
  214. /****************************************************************************
  215. * Public Functions
  216. ****************************************************************************/
  217. /****************************************************************************
  218. * Name: shmget
  219. *
  220. * Description:
  221. * The shmget() function will return the shared memory identifier
  222. * associated with key.
  223. *
  224. * A shared memory identifier, associated data structure, and shared
  225. * memory segment of at least size bytes is created for key if one of the
  226. * following is true:
  227. *
  228. * - The argument key is equal to IPC_PRIVATE.
  229. * - The argument key does not already have a shared memory identifier
  230. * associated with it and (shmflg & IPC_CREAT) is non-zero.
  231. *
  232. * Upon creation, the data structure associated with the new shared memory
  233. * identifier will be initialized as follows:
  234. *
  235. * - The low-order nine bits of shm_perm.mode are set equal to the low-
  236. * order nine bits of shmflg.
  237. * - The value of shm_segsz is set equal to the value of size.
  238. * - The values of shm_lpid, shm_nattch, shm_atime, and shm_dtime are
  239. * set equal to 0.
  240. * - The value of shm_ctime is set equal to the current time.
  241. *
  242. * When the shared memory segment is created, it will be initialized with
  243. * all zero values.
  244. *
  245. * Input Parameters:
  246. * key - The key that is used to access the unique shared memory
  247. * identifier.
  248. * size - The shared memory region that is created will be at least
  249. * this size in bytes.
  250. * shmflgs - See IPC_* definitions in sys/ipc.h. Only the values
  251. * IPC_PRIVATE or IPC_CREAT are supported.
  252. *
  253. * Returned Value:
  254. * Upon successful completion, shmget() will return a non-negative
  255. * integer, namely a shared memory identifier; otherwise, it will return
  256. * -1 and set errno to indicate the error.
  257. *
  258. * - EACCES
  259. * A shared memory identifier exists for key but operation permission
  260. * as specified by the low-order nine bits of shmflg would not be
  261. * granted.
  262. * - EEXIST
  263. * A shared memory identifier exists for the argument key but
  264. * (shmflg & IPC_CREAT) && (shmflg & IPC_EXCL) are non-zero.
  265. * - EINVAL
  266. * A shared memory segment is to be created and the value of size is
  267. * less than the system-imposed minimum or greater than the system-
  268. * imposed maximum.
  269. * - EINVAL
  270. * No shared memory segment is to be created and a shared memory
  271. * segment exists for key but the size of the segment associated with
  272. * it is less than size and size is not 0.
  273. * - ENOENT
  274. * A shared memory identifier does not exist for the argument key and
  275. * (shmflg & IPC_CREAT) is 0.
  276. * - ENOMEM
  277. * A shared memory identifier and associated shared memory segment
  278. * will be created, but the amount of available physical memory is
  279. * not sufficient to fill the request.
  280. * - ENOSPC
  281. * A shared memory identifier is to be created, but the system-imposed
  282. * limit on the maximum number of allowed shared memory identifiers
  283. * system-wide would be exceeded.
  284. *
  285. * POSIX Deviations:
  286. * - The values of shm_perm.cuid, shm_perm.uid, shm_perm.cgid, and
  287. * shm_perm.gid should be set equal to the effective user ID and
  288. * effective group ID, respectively, of the calling process.
  289. * The NuttX ipc_perm structure, however, does not support these
  290. * fields because user and group IDs are not yet supported by NuttX.
  291. *
  292. ****************************************************************************/
  293. int shmget(key_t key, size_t size, int shmflg)
  294. {
  295. FAR struct shm_region_s *region;
  296. int shmid = -1;
  297. int ret;
  298. /* Check for the special case where the caller doesn't really want shared
  299. * memory (they why do they bother to call us?)
  300. */
  301. if (key == IPC_PRIVATE)
  302. {
  303. /* Not yet implemented */
  304. ret = -ENOSYS;
  305. goto errout;
  306. }
  307. /* Get exclusive access to the global list of shared memory regions */
  308. ret = nxsem_wait(&g_shminfo.si_sem);
  309. if (ret < 0)
  310. {
  311. goto errout;
  312. }
  313. /* Find the requested memory region */
  314. ret = shm_find(key);
  315. if (ret < 0)
  316. {
  317. /* The memory region does not exist.. create it if IPC_CREAT is
  318. * included in the shmflags.
  319. */
  320. if ((shmflg & IPC_CREAT) != 0)
  321. {
  322. /* Create the memory region */
  323. ret = shm_create(key, size, shmflg);
  324. if (ret < 0)
  325. {
  326. shmerr("ERROR: shm_create failed: %d\n", ret);
  327. goto errout_with_semaphore;
  328. }
  329. /* Return the shared memory ID */
  330. shmid = ret;
  331. }
  332. else
  333. {
  334. /* Fail with ENOENT */
  335. goto errout_with_semaphore;
  336. }
  337. }
  338. /* The region exists */
  339. else
  340. {
  341. /* Remember the shared memory ID */
  342. shmid = ret;
  343. /* Is the region big enough for the request? */
  344. region = &g_shminfo.si_region[shmid];
  345. if (region->sr_ds.shm_segsz < size)
  346. {
  347. /* We we asked to create the region? If so we can just
  348. * extend it.
  349. *
  350. * REVISIT: We should check the mode bits of the regions
  351. * first
  352. */
  353. if ((shmflg & IPC_CREAT) != 0)
  354. {
  355. /* Extend the region */
  356. ret = shm_extend(shmid, size);
  357. if (ret < 0)
  358. {
  359. shmerr("ERROR: shm_create failed: %d\n", ret);
  360. goto errout_with_semaphore;
  361. }
  362. }
  363. else
  364. {
  365. /* Fail with EINVAL */
  366. ret = -EINVAL;
  367. goto errout_with_semaphore;
  368. }
  369. }
  370. /* The region is already big enough or else we successfully
  371. * extended the size of the region. If the region was previously
  372. * deleted, but waiting for processes to detach from the region,
  373. * then it is no longer deleted.
  374. */
  375. region->sr_flags = SRFLAG_INUSE;
  376. }
  377. /* Release our lock on the shared memory region list */
  378. nxsem_post(&g_shminfo.si_sem);
  379. return shmid;
  380. errout_with_semaphore:
  381. nxsem_post(&g_shminfo.si_sem);
  382. errout:
  383. set_errno(-ret);
  384. return ERROR;
  385. }
  386. #endif /* CONFIG_MM_SHM */