shmat.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /****************************************************************************
  2. * mm/shm/shmat.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 <assert.h>
  26. #include <errno.h>
  27. #include <nuttx/sched.h>
  28. #include <nuttx/arch.h>
  29. #include <nuttx/pgalloc.h>
  30. #include "shm/shm.h"
  31. #ifdef CONFIG_MM_SHM
  32. /****************************************************************************
  33. * Public Functions
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Name: shmat
  37. *
  38. * Description:
  39. * The shmat() function attaches the shared memory segment associated with
  40. * the shared memory identifier specified by shmid to the address space of
  41. * the calling process. The segment is attached at the address specified
  42. * by one of the following criteria:
  43. *
  44. * - If shmaddr is a null pointer, the segment is attached at the first
  45. * available address as selected by the system.
  46. * - If shmaddr is not a null pointer and (shmflg & SHM_RND) is non-
  47. * zero, the segment is attached at the address given by
  48. * (shmaddr - ((uintptr_t)shmaddr % SHMLBA)).
  49. * - If shmaddr is not a null pointer and (shmflg & SHM_RND) is 0, the
  50. * segment is attached at the address given by shmaddr.
  51. * - The segment is attached for reading if (shmflg & SHM_RDONLY) is
  52. * non-zero and the calling process has read permission; otherwise, if
  53. * it is 0 and the calling process has read and write permission, the
  54. * segment is attached for reading and writing.
  55. *
  56. * Input Parameters:
  57. * shmid - Shared memory identifier
  58. * smaddr - Determines mapping of the shared memory region
  59. * shmflg - See SHM_* definitions in include/sys/shm.h. Only SHM_RDONLY
  60. * and SHM_RND are supported.
  61. *
  62. * Returned Value:
  63. * Upon successful completion, shmat() will increment the value of
  64. * shm_nattch in the data structure associated with the shared memory ID
  65. * of the attached shared memory segment and return the segment's start
  66. * address.
  67. *
  68. * Otherwise, the shared memory segment will not be attached, shmat() will
  69. * return -1, and errno will be set to indicate the error.
  70. *
  71. * - EACCES
  72. * Operation permission is denied to the calling process
  73. * - EINVAL
  74. * The value of shmid is not a valid shared memory identifier, the
  75. * shmaddr is not a null pointer, and the value of
  76. * (shmaddr -((uintptr_t)shmaddr % SHMLBA)) is an illegal address for
  77. * attaching shared memory; or the shmaddr is not a null pointer,
  78. * (shmflg & SHM_RND) is 0, and the value of shmaddr is an illegal
  79. * address for attaching shared memory.
  80. * - EMFILE
  81. * The number of shared memory segments attached to the calling
  82. * process would exceed the system-imposed limit.
  83. * - ENOMEM
  84. * The available data space is not large enough to accommodate the
  85. * shared memory segment.
  86. *
  87. ****************************************************************************/
  88. FAR void *shmat(int shmid, FAR const void *shmaddr, int shmflg)
  89. {
  90. FAR struct shm_region_s *region;
  91. FAR struct task_group_s *group;
  92. FAR struct tcb_s *tcb;
  93. uintptr_t vaddr;
  94. unsigned int npages;
  95. int ret;
  96. /* Get the region associated with the shmid */
  97. DEBUGASSERT(shmid >= 0 && shmid < CONFIG_ARCH_SHM_MAXREGIONS);
  98. region = &g_shminfo.si_region[shmid];
  99. DEBUGASSERT((region->sr_flags & SRFLAG_INUSE) != 0);
  100. /* Get the TCB and group containing our virtual memory allocator */
  101. tcb = nxsched_self();
  102. DEBUGASSERT(tcb && tcb->group);
  103. group = tcb->group;
  104. DEBUGASSERT(group->tg_shm.gs_handle != NULL &&
  105. group->tg_shm.gs_vaddr[shmid] == 0);
  106. /* Get exclusive access to the region data structure */
  107. ret = nxsem_wait(&region->sr_sem);
  108. if (ret < 0)
  109. {
  110. shmerr("ERROR: nxsem_wait failed: %d\n", ret);
  111. goto errout_with_ret;
  112. }
  113. /* Set aside a virtual address space to span this physical region */
  114. vaddr = (uintptr_t)gran_alloc(group->tg_shm.gs_handle,
  115. region->sr_ds.shm_segsz);
  116. if (vaddr == 0)
  117. {
  118. shmerr("ERROR: gran_alloc() failed\n");
  119. ret = -ENOMEM;
  120. goto errout_with_semaphore;
  121. }
  122. /* Convert the region size to pages */
  123. npages = MM_NPAGES(region->sr_ds.shm_segsz);
  124. /* Attach, i.e, map, on shared memory region to the user virtual address. */
  125. ret = up_shmat(region->sr_pages, npages, vaddr);
  126. if (ret < 0)
  127. {
  128. shmerr("ERROR: up_shmat() failed\n");
  129. goto errout_with_vaddr;
  130. }
  131. /* Save the virtual address of the region. We will need that in shmat()
  132. * to do the reverse lookup: Give the virtual address of the region to
  133. * detach, we need to get the region table index.
  134. */
  135. group->tg_shm.gs_vaddr[shmid] = vaddr;
  136. /* Increment the count of processes attached to this region */
  137. region->sr_ds.shm_nattch++;
  138. /* Save the process ID of the last operation */
  139. region->sr_ds.shm_lpid = tcb->pid;
  140. /* Save the time of the last shmat() */
  141. region->sr_ds.shm_atime = time(NULL);
  142. /* Release our lock on the entry */
  143. nxsem_post(&region->sr_sem);
  144. return (FAR void *)vaddr;
  145. errout_with_vaddr:
  146. gran_free(group->tg_shm.gs_handle, (FAR void *)vaddr,
  147. region->sr_ds.shm_segsz);
  148. errout_with_semaphore:
  149. nxsem_post(&region->sr_sem);
  150. errout_with_ret:
  151. set_errno(-ret);
  152. return (FAR void *)ERROR;
  153. }
  154. #endif /* CONFIG_MM_SHM */