shmctl.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /****************************************************************************
  2. * mm/shm/shmctl.c
  3. *
  4. * Copyright (C) 2014, 2017 Gregory Nutt. All rights reserved.
  5. * Author: Gregory Nutt <gnutt@nuttx.org>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #include <sys/shm.h>
  40. #include <sys/ipc.h>
  41. #include <unistd.h>
  42. #include <string.h>
  43. #include <semaphore.h>
  44. #include <time.h>
  45. #include <errno.h>
  46. #include <assert.h>
  47. #include <nuttx/mm/shm.h>
  48. #include <nuttx/pgalloc.h>
  49. #include "shm/shm.h"
  50. #ifdef CONFIG_MM_SHM
  51. /****************************************************************************
  52. * Public Functions
  53. ****************************************************************************/
  54. /****************************************************************************
  55. * Name: shmctl
  56. *
  57. * Description:
  58. * The shmctl() function provides a variety of shared memory control
  59. * operations as specified by cmd. The following values for cmd are
  60. * available:
  61. *
  62. * - IPC_STAT
  63. * Place the current value of each member of the shmid_ds data
  64. * structure associated with shmid into the structure pointed to by
  65. * buf.
  66. * - IPC_SET
  67. * Set the value of the shm_perm.mode member of the shmid_ds data
  68. * structure associated with shmid to the corresponding value found
  69. * in the structure pointed to by buf.
  70. * - IPC_RMID
  71. * Remove the shared memory identifier specified by shmid from the
  72. * system and destroy the shared memory segment and shmid_ds data
  73. * structure associated with it.
  74. *
  75. * Input Parameters:
  76. * shmid - Shared memory identifier
  77. * cmd - shmctl() command
  78. * buf - Data associated with the shmctl() command
  79. *
  80. * Returned Value:
  81. * Upon successful completion, shmctl() will return 0; otherwise, it will
  82. * return -1 and set errno to indicate the error.
  83. *
  84. * - EACCES
  85. * The argument cmd is equal to IPC_STAT and the calling process does
  86. * not have read permission.
  87. * - EINVAL
  88. * The value of shmid is not a valid shared memory identifier, or the
  89. * value of cmd is not a valid command.
  90. * - EPERM
  91. * The argument cmd is equal to IPC_RMID or IPC_SET and the effective
  92. * user ID of the calling process is not equal to that of a process
  93. * with appropriate privileges and it is not equal to the value of
  94. * shm_perm.cuid or shm_perm.uid in the data structure associated with
  95. * shmid.
  96. * - EOVERFLOW
  97. * The cmd argument is IPC_STAT and the gid or uid value is too large
  98. * to be stored in the structure pointed to by the buf argument.
  99. *
  100. * POSIX Deviations:
  101. * - IPC_SET. Does not set the shm_perm.uid or shm_perm.gid
  102. * members of the shmid_ds data structure associated with shmid
  103. * because user and group IDs are not yet supported by NuttX
  104. * - IPC_SET. Does not restrict the operation to processes with
  105. * appropriate privileges or matching user IDs in shmid_ds data
  106. * structure associated with shmid. Again because user IDs and
  107. * user/group privileges are are not yet supported by NuttX
  108. * - IPC_RMID. Does not restrict the operation to processes with
  109. * appropriate privileges or matching user IDs in shmid_ds data
  110. * structure associated with shmid. Again because user IDs and
  111. * user/group privileges are are not yet supported by NuttX
  112. *
  113. ****************************************************************************/
  114. int shmctl(int shmid, int cmd, struct shmid_ds *buf)
  115. {
  116. FAR struct shm_region_s *region;
  117. int ret;
  118. DEBUGASSERT(shmid >= 0 && shmid < CONFIG_ARCH_SHM_MAXREGIONS);
  119. region = &g_shminfo.si_region[shmid];
  120. DEBUGASSERT((region->sr_flags & SRFLAG_INUSE) != 0);
  121. /* Get exclusive access to the region data structure */
  122. ret = nxsem_wait(&region->sr_sem);
  123. if (ret < 0)
  124. {
  125. shmerr("ERROR: nxsem_wait failed: %d\n", ret);
  126. goto errout_with_ret;
  127. }
  128. /* Handle the request according to the received cmd */
  129. switch (cmd)
  130. {
  131. case IPC_STAT:
  132. {
  133. /* Place the current value of each member of the shmid_ds data
  134. * structure associated with shmid into the structure pointed to
  135. * by buf.
  136. */
  137. DEBUGASSERT(buf);
  138. memcpy(buf, &region->sr_ds, sizeof(struct shmid_ds));
  139. }
  140. break;
  141. case IPC_SET:
  142. {
  143. /* Set the value of the shm_perm.mode member of the shmid_ds
  144. * data structure associated with shmid to the corresponding
  145. * value found in the structure pointed to by buf.
  146. */
  147. region->sr_ds.shm_perm.mode = buf->shm_perm.mode;
  148. }
  149. break;
  150. case IPC_RMID:
  151. {
  152. /* Are any processes attached to the region? */
  153. if (region->sr_ds.shm_nattch > 0)
  154. {
  155. /* Yes.. just set the UNLINKED flag. The region will be
  156. * removed when there are no longer any processes attached to
  157. * it.
  158. */
  159. region->sr_flags |= SRFLAG_UNLINKED;
  160. }
  161. else
  162. {
  163. /* No.. free the entry now */
  164. shm_destroy(shmid);
  165. /* Don't try anything further on the deleted region */
  166. return OK;
  167. }
  168. }
  169. break;
  170. default:
  171. shmerr("ERROR: Unrecognized command: %d\n", cmd);
  172. ret = -EINVAL;
  173. goto errout_with_semaphore;
  174. }
  175. /* Save the process ID of the last operation */
  176. region = &g_shminfo.si_region[shmid];
  177. region->sr_ds.shm_lpid = getpid();
  178. /* Save the time of the last shmctl() */
  179. region->sr_ds.shm_ctime = time(NULL);
  180. /* Release our lock on the entry */
  181. nxsem_post(&region->sr_sem);
  182. return ret;
  183. errout_with_semaphore:
  184. nxsem_post(&region->sr_sem);
  185. errout_with_ret:
  186. set_errno(-ret);
  187. return ERROR;
  188. }
  189. /****************************************************************************
  190. * Name: shm_destroy
  191. *
  192. * Description:
  193. * Destroy a memory region. This function is called:
  194. *
  195. * - On certain conditions when shmget() is not successful in instantiating
  196. * the full memory region and we need to clean up and free a table entry.
  197. * - When shmctl() is called with cmd == IPC_RMID and there are no
  198. * processes attached to the memory region.
  199. * - When shmdt() is called after the last process detaches from memory
  200. * region after it was previously marked for deletion by shmctl().
  201. *
  202. * Input Parameters:
  203. * shmid - Shared memory identifier
  204. *
  205. * Returned Value:
  206. * None
  207. *
  208. * Assumption:
  209. * The caller holds either the region table semaphore or else the
  210. * semaphore on the particular entry being deleted.
  211. *
  212. ****************************************************************************/
  213. void shm_destroy(int shmid)
  214. {
  215. FAR struct shm_region_s *region = &g_shminfo.si_region[shmid];
  216. int i;
  217. /* Free all of the allocated physical pages */
  218. for (i = 0; i < CONFIG_ARCH_SHM_NPAGES && region->sr_pages[i] != 0; i++)
  219. {
  220. mm_pgfree(region->sr_pages[i], 1);
  221. }
  222. /* Reset the region entry to its initial state */
  223. nxsem_destroy(&region->sr_sem);
  224. memset(region, 0, sizeof(struct shm_region_s));
  225. }
  226. #endif /* CONFIG_MM_SHM */