ipc_pset.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*
  2. * Mach Operating System
  3. * Copyright (c) 1991,1990,1989Carnegie Mellon University.
  4. * Copyright (c) 1993,1994 The University of Utah and
  5. * the Computer Systems Laboratory (CSL).
  6. * All rights reserved.
  7. *
  8. * Permission to use, copy, modify and distribute this software and its
  9. * documentation is hereby granted, provided that both the copyright
  10. * notice and this permission notice appear in all copies of the
  11. * software, derivative works or modified versions, and any portions
  12. * thereof, and that both notices appear in supporting documentation.
  13. *
  14. * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
  15. * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
  16. * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
  17. * THIS SOFTWARE.
  18. *
  19. * Carnegie Mellon requests users of this software to return to
  20. *
  21. * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
  22. * School of Computer Science
  23. * Carnegie Mellon University
  24. * Pittsburgh PA 15213-3890
  25. *
  26. * any improvements or extensions that they make and grant Carnegie Mellon
  27. * the rights to redistribute these changes.
  28. */
  29. /*
  30. */
  31. /*
  32. * File: ipc/ipc_pset.c
  33. * Author: Rich Draves
  34. * Date: 1989
  35. *
  36. * Functions to manipulate IPC port sets.
  37. */
  38. #pragma GCC diagnostic error "-Wundef"
  39. #include <glue/gnulinux.h>
  40. #include <kern/printf.h>
  41. #include <mach/port.h>
  42. #include <mach/kern_return.h>
  43. #include <mach/message.h>
  44. #include <ipc/ipc_mqueue.h>
  45. #include <ipc/ipc_object.h>
  46. #include <ipc/ipc_pset.h>
  47. #include <ipc/ipc_right.h>
  48. #include <ipc/ipc_space.h>
  49. #if MACH_KDB
  50. #include <ddb/db_output.h>
  51. #include <ipc/ipc_print.h>
  52. #endif /* MACH_KDB */
  53. /*
  54. * Routine: ipc_pset_alloc
  55. * Purpose:
  56. * Allocate a port set.
  57. * Conditions:
  58. * Nothing locked. If successful, the port set is returned
  59. * locked. (The caller doesn't have a reference.)
  60. * Returns:
  61. * KERN_SUCCESS The port set is allocated.
  62. * KERN_INVALID_TASK The space is dead.
  63. * KERN_NO_SPACE No room for an entry in the space.
  64. * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
  65. */
  66. kern_return_t
  67. ipc_pset_alloc(
  68. ipc_space_t space,
  69. mach_port_t *namep,
  70. ipc_pset_t *psetp)
  71. {
  72. ipc_pset_t pset;
  73. mach_port_t name;
  74. kern_return_t kr;
  75. kr = ipc_object_alloc(space, IOT_PORT_SET,
  76. MACH_PORT_TYPE_PORT_SET, 0,
  77. &name, (ipc_object_t *) &pset);
  78. if (kr != KERN_SUCCESS)
  79. return kr;
  80. /* pset is locked */
  81. ipc_target_init(&pset->ips_target, name);
  82. *namep = name;
  83. *psetp = pset;
  84. return KERN_SUCCESS;
  85. }
  86. /*
  87. * Routine: ipc_pset_alloc_name
  88. * Purpose:
  89. * Allocate a port set, with a specific name.
  90. * Conditions:
  91. * Nothing locked. If successful, the port set is returned
  92. * locked. (The caller doesn't have a reference.)
  93. * Returns:
  94. * KERN_SUCCESS The port set is allocated.
  95. * KERN_INVALID_TASK The space is dead.
  96. * KERN_NAME_EXISTS The name already denotes a right.
  97. * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
  98. */
  99. kern_return_t
  100. ipc_pset_alloc_name(
  101. ipc_space_t space,
  102. mach_port_t name,
  103. ipc_pset_t *psetp)
  104. {
  105. ipc_pset_t pset;
  106. kern_return_t kr;
  107. kr = ipc_object_alloc_name(space, IOT_PORT_SET,
  108. MACH_PORT_TYPE_PORT_SET, 0,
  109. name, (ipc_object_t *) &pset);
  110. if (kr != KERN_SUCCESS)
  111. return kr;
  112. /* pset is locked */
  113. ipc_target_init(&pset->ips_target, name);
  114. *psetp = pset;
  115. return KERN_SUCCESS;
  116. }
  117. /*
  118. * Routine: ipc_pset_add
  119. * Purpose:
  120. * Puts a port into a port set.
  121. * The port set gains a reference.
  122. * Conditions:
  123. * Both port and port set are locked and active.
  124. * The port isn't already in a set.
  125. * The owner of the port set is also receiver for the port.
  126. */
  127. void
  128. ipc_pset_add(
  129. ipc_pset_t pset,
  130. ipc_port_t port)
  131. {
  132. assert(ips_active(pset));
  133. assert(ip_active(port));
  134. assert(port->ip_pset == IPS_NULL);
  135. port->ip_pset = pset;
  136. port->ip_cur_target = &pset->ips_target;
  137. ips_reference(pset);
  138. imq_lock(&port->ip_messages);
  139. imq_lock(&pset->ips_messages);
  140. /* move messages from port's queue to the port set's queue */
  141. ipc_mqueue_move(&pset->ips_messages, &port->ip_messages, port);
  142. imq_unlock(&pset->ips_messages);
  143. assert(ipc_kmsg_queue_empty(&port->ip_messages.imq_messages));
  144. /* wake up threads waiting to receive from the port */
  145. ipc_mqueue_changed(&port->ip_messages, MACH_RCV_PORT_CHANGED);
  146. assert(ipc_thread_queue_empty(&port->ip_messages.imq_threads));
  147. imq_unlock(&port->ip_messages);
  148. }
  149. /*
  150. * Routine: ipc_pset_remove
  151. * Purpose:
  152. * Removes a port from a port set.
  153. * The port set loses a reference.
  154. * Conditions:
  155. * Both port and port set are locked.
  156. * The port must be active.
  157. */
  158. void
  159. ipc_pset_remove(
  160. ipc_pset_t pset,
  161. ipc_port_t port)
  162. {
  163. assert(ip_active(port));
  164. assert(port->ip_pset == pset);
  165. port->ip_pset = IPS_NULL;
  166. port->ip_cur_target = &port->ip_target;
  167. ips_release(pset);
  168. imq_lock(&port->ip_messages);
  169. imq_lock(&pset->ips_messages);
  170. /* move messages from port set's queue to the port's queue */
  171. ipc_mqueue_move(&port->ip_messages, &pset->ips_messages, port);
  172. imq_unlock(&pset->ips_messages);
  173. imq_unlock(&port->ip_messages);
  174. }
  175. /*
  176. * Routine: ipc_pset_move
  177. * Purpose:
  178. * If nset is IPS_NULL, removes port
  179. * from the port set it is in. Otherwise, adds
  180. * port to nset, removing it from any set
  181. * it might already be in.
  182. * Conditions:
  183. * The space is read-locked.
  184. * Returns:
  185. * KERN_SUCCESS Moved the port.
  186. * KERN_NOT_IN_SET nset is null and port isn't in a set.
  187. */
  188. kern_return_t
  189. ipc_pset_move(
  190. ipc_space_t space,
  191. ipc_port_t port,
  192. ipc_pset_t nset)
  193. {
  194. ipc_pset_t oset;
  195. /*
  196. * While we've got the space locked, it holds refs for
  197. * the port and nset (because of the entries). Also,
  198. * they must be alive. While we've got port locked, it
  199. * holds a ref for oset, which might not be alive.
  200. */
  201. ip_lock(port);
  202. assert(ip_active(port));
  203. oset = port->ip_pset;
  204. if (oset == nset) {
  205. /* the port is already in the new set: a noop */
  206. is_read_unlock(space);
  207. } else if (oset == IPS_NULL) {
  208. /* just add port to the new set */
  209. ips_lock(nset);
  210. assert(ips_active(nset));
  211. is_read_unlock(space);
  212. ipc_pset_add(nset, port);
  213. ips_unlock(nset);
  214. } else if (nset == IPS_NULL) {
  215. /* just remove port from the old set */
  216. is_read_unlock(space);
  217. ips_lock(oset);
  218. ipc_pset_remove(oset, port);
  219. if (ips_active(oset))
  220. ips_unlock(oset);
  221. else {
  222. ips_check_unlock(oset);
  223. oset = IPS_NULL; /* trigger KERN_NOT_IN_SET */
  224. }
  225. } else {
  226. /* atomically move port from oset to nset */
  227. if (oset < nset) {
  228. ips_lock(oset);
  229. ips_lock(nset);
  230. } else {
  231. ips_lock(nset);
  232. ips_lock(oset);
  233. }
  234. is_read_unlock(space);
  235. assert(ips_active(nset));
  236. ipc_pset_remove(oset, port);
  237. ipc_pset_add(nset, port);
  238. ips_unlock(nset);
  239. ips_check_unlock(oset); /* KERN_NOT_IN_SET not a possibility */
  240. }
  241. ip_unlock(port);
  242. return (((nset == IPS_NULL) && (oset == IPS_NULL)) ?
  243. KERN_NOT_IN_SET : KERN_SUCCESS);
  244. }
  245. /*
  246. * Routine: ipc_pset_destroy
  247. * Purpose:
  248. * Destroys a port_set.
  249. *
  250. * Doesn't remove members from the port set;
  251. * that happens lazily. As members are removed,
  252. * their messages are removed from the queue.
  253. * Conditions:
  254. * The port_set is locked and alive.
  255. * The caller has a reference, which is consumed.
  256. * Afterwards, the port_set is unlocked and dead.
  257. */
  258. void
  259. ipc_pset_destroy(
  260. ipc_pset_t pset)
  261. {
  262. assert(ips_active(pset));
  263. pset->ips_object.io_bits &= ~IO_BITS_ACTIVE;
  264. imq_lock(&pset->ips_messages);
  265. ipc_mqueue_changed(&pset->ips_messages, MACH_RCV_PORT_DIED);
  266. imq_unlock(&pset->ips_messages);
  267. /* Common destruction for the IPC target. */
  268. ipc_target_terminate(&pset->ips_target);
  269. ips_release(pset); /* consume the ref our caller gave us */
  270. ips_check_unlock(pset);
  271. }
  272. #if MACH_KDB
  273. #define printf kdbprintf
  274. /*
  275. * Routine: ipc_pset_print
  276. * Purpose:
  277. * Pretty-print a port set for kdb.
  278. */
  279. void
  280. ipc_pset_print(
  281. const ipc_pset_t pset)
  282. {
  283. printf("pset 0x%x\n", pset);
  284. indent += 2;
  285. ipc_object_print(&pset->ips_object);
  286. iprintf("local_name = 0x%x\n", pset->ips_local_name);
  287. iprintf("kmsgs = 0x%x", pset->ips_messages.imq_messages.ikmq_base);
  288. printf(",rcvrs = 0x%x\n", pset->ips_messages.imq_threads.ithq_base);
  289. indent -= 2;
  290. }
  291. #endif /* MACH_KDB */