ipc_marequest.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. /*
  2. * Mach Operating System
  3. * Copyright (c) 1991,1990,1989 Carnegie 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. * File: ipc/ipc_marequest.c
  31. * Author: Rich Draves
  32. * Date: 1989
  33. *
  34. * Functions to handle msg-accepted requests.
  35. */
  36. #pragma GCC diagnostic error "-Wundef"
  37. #include <glue/gnulinux.h>
  38. #include <mach/message.h>
  39. #include <mach/port.h>
  40. #include <kern/lock.h>
  41. #include <kern/kalloc.h>
  42. #include <kern/slab.h>
  43. #include <ipc/port.h>
  44. #include <ipc/ipc_init.h>
  45. #include <ipc/ipc_space.h>
  46. #include <ipc/ipc_entry.h>
  47. #include <ipc/ipc_port.h>
  48. #include <ipc/ipc_right.h>
  49. #include <ipc/ipc_marequest.h>
  50. #include <ipc/ipc_notify.h>
  51. #if MACH_IPC_DEBUG
  52. #include <mach/kern_return.h>
  53. #include <mach_debug/hash_info.h>
  54. #include <vm/vm_map.h>
  55. #include <vm/vm_kern.h>
  56. #include <vm/vm_user.h>
  57. #endif
  58. struct gnu_kmem_cache ipc_marequest_cache;
  59. #define imar_alloc() ((ipc_marequest_t) gnu_kmem_cache_alloc(&ipc_marequest_cache))
  60. #define imar_free(imar) gnu_kmem_cache_free(&ipc_marequest_cache, (vm_offset_t) (imar))
  61. typedef unsigned int ipc_marequest_index_t;
  62. ipc_marequest_index_t ipc_marequest_size;
  63. ipc_marequest_index_t ipc_marequest_mask;
  64. #define IMAR_HASH(space, name) \
  65. ((((ipc_marequest_index_t)((vm_offset_t)space) >> 4) + \
  66. MACH_PORT_INDEX(name) + MACH_PORT_NGEN(name)) & \
  67. ipc_marequest_mask)
  68. typedef struct ipc_marequest_bucket {
  69. decl_simple_lock_data(, imarb_lock_data)
  70. ipc_marequest_t imarb_head;
  71. } *ipc_marequest_bucket_t;
  72. #define IMARB_NULL ((ipc_marequest_bucket_t) 0)
  73. #define imarb_lock_init(imarb) simple_lock_init(&(imarb)->imarb_lock_data)
  74. #define imarb_lock(imarb) simple_lock(&(imarb)->imarb_lock_data)
  75. #define imarb_unlock(imarb) simple_unlock(&(imarb)->imarb_lock_data)
  76. ipc_marequest_bucket_t ipc_marequest_table;
  77. /*
  78. * Routine: ipc_marequest_init
  79. * Purpose:
  80. * Initialize the msg-accepted request module.
  81. */
  82. void
  83. ipc_marequest_init(void)
  84. {
  85. ipc_marequest_index_t i;
  86. /* initialize ipc_marequest_size */
  87. ipc_marequest_size = IPC_MAREQUEST_SIZE;
  88. /* make sure it is a power of two */
  89. ipc_marequest_mask = ipc_marequest_size - 1;
  90. if ((ipc_marequest_size & ipc_marequest_mask) != 0) {
  91. unsigned int bit;
  92. /* round up to closest power of two */
  93. for (bit = 1;; bit <<= 1) {
  94. ipc_marequest_mask |= bit;
  95. ipc_marequest_size = ipc_marequest_mask + 1;
  96. if ((ipc_marequest_size & ipc_marequest_mask) == 0)
  97. break;
  98. }
  99. }
  100. /* allocate ipc_marequest_table */
  101. ipc_marequest_table = (ipc_marequest_bucket_t)
  102. kalloc((vm_size_t) (ipc_marequest_size *
  103. sizeof(struct ipc_marequest_bucket)));
  104. assert(ipc_marequest_table != IMARB_NULL);
  105. /* and initialize it */
  106. for (i = 0; i < ipc_marequest_size; i++) {
  107. ipc_marequest_bucket_t bucket;
  108. bucket = &ipc_marequest_table[i];
  109. imarb_lock_init(bucket);
  110. bucket->imarb_head = IMAR_NULL;
  111. }
  112. gnu_kmem_cache_init(&ipc_marequest_cache, "ipc_marequest",
  113. sizeof(struct ipc_marequest), 0, NULL, 0);
  114. }
  115. /*
  116. * Routine: ipc_marequest_create
  117. * Purpose:
  118. * Create a msg-accepted request, because
  119. * a sender is forcing a message with MACH_SEND_NOTIFY.
  120. *
  121. * The "notify" argument should name a receive right
  122. * that is used to create the send-once notify port.
  123. * Conditions:
  124. * Nothing locked; refs held for space and port.
  125. * Returns:
  126. * MACH_MSG_SUCCESS Msg-accepted request created.
  127. * MACH_SEND_INVALID_NOTIFY The space is dead.
  128. * MACH_SEND_INVALID_NOTIFY The notify port is bad.
  129. * MACH_SEND_NOTIFY_IN_PROGRESS
  130. * This space has already forced a message to this port.
  131. * MACH_SEND_NO_NOTIFY Can't allocate a msg-accepted request.
  132. */
  133. mach_msg_return_t
  134. ipc_marequest_create(
  135. ipc_space_t space,
  136. ipc_port_t port,
  137. mach_port_t notify,
  138. ipc_marequest_t *marequestp)
  139. {
  140. mach_port_t name;
  141. ipc_entry_t entry;
  142. ipc_port_t soright;
  143. ipc_marequest_t marequest;
  144. ipc_marequest_bucket_t bucket;
  145. marequest = imar_alloc();
  146. if (marequest == IMAR_NULL)
  147. return MACH_SEND_NO_NOTIFY;
  148. /*
  149. * Delay creating the send-once right until
  150. * we know there will be no errors. Otherwise,
  151. * we would have to worry about disposing of it
  152. * when it turned out it wasn't needed.
  153. */
  154. is_write_lock(space);
  155. if (!space->is_active) {
  156. is_write_unlock(space);
  157. imar_free(marequest);
  158. return MACH_SEND_INVALID_NOTIFY;
  159. }
  160. if (ipc_right_reverse(space, (ipc_object_t) port, &name, &entry)) {
  161. ipc_entry_bits_t bits;
  162. /* port is locked and active */
  163. ip_unlock(port);
  164. bits = entry->ie_bits;
  165. assert(port == (ipc_port_t) entry->ie_object);
  166. assert(bits & MACH_PORT_TYPE_SEND_RECEIVE);
  167. if (bits & IE_BITS_MAREQUEST) {
  168. is_write_unlock(space);
  169. imar_free(marequest);
  170. return MACH_SEND_NOTIFY_IN_PROGRESS;
  171. }
  172. if ((soright = ipc_port_lookup_notify(space, notify))
  173. == IP_NULL) {
  174. is_write_unlock(space);
  175. imar_free(marequest);
  176. return MACH_SEND_INVALID_NOTIFY;
  177. }
  178. entry->ie_bits = bits | IE_BITS_MAREQUEST;
  179. is_reference(space);
  180. marequest->imar_space = space;
  181. marequest->imar_name = name;
  182. marequest->imar_soright = soright;
  183. bucket = &ipc_marequest_table[IMAR_HASH(space, name)];
  184. imarb_lock(bucket);
  185. marequest->imar_next = bucket->imarb_head;
  186. bucket->imarb_head = marequest;
  187. imarb_unlock(bucket);
  188. } else {
  189. if ((soright = ipc_port_lookup_notify(space, notify))
  190. == IP_NULL) {
  191. is_write_unlock(space);
  192. imar_free(marequest);
  193. return MACH_SEND_INVALID_NOTIFY;
  194. }
  195. is_reference(space);
  196. marequest->imar_space = space;
  197. marequest->imar_name = MACH_PORT_NULL;
  198. marequest->imar_soright = soright;
  199. }
  200. is_write_unlock(space);
  201. *marequestp = marequest;
  202. return MACH_MSG_SUCCESS;
  203. }
  204. /*
  205. * Routine: ipc_marequest_cancel
  206. * Purpose:
  207. * Cancel a msg-accepted request, because
  208. * the space's entry is being destroyed.
  209. * Conditions:
  210. * The space is write-locked and active.
  211. */
  212. void
  213. ipc_marequest_cancel(
  214. ipc_space_t space,
  215. mach_port_t name)
  216. {
  217. ipc_marequest_bucket_t bucket;
  218. ipc_marequest_t marequest, *last;
  219. assert(space->is_active);
  220. bucket = &ipc_marequest_table[IMAR_HASH(space, name)];
  221. imarb_lock(bucket);
  222. for (last = &bucket->imarb_head;
  223. (marequest = *last) != IMAR_NULL;
  224. last = &marequest->imar_next)
  225. if ((marequest->imar_space == space) &&
  226. (marequest->imar_name == name))
  227. break;
  228. assert(marequest != IMAR_NULL);
  229. *last = marequest->imar_next;
  230. imarb_unlock(bucket);
  231. marequest->imar_name = MACH_PORT_NULL;
  232. }
  233. /*
  234. * Routine: ipc_marequest_rename
  235. * Purpose:
  236. * Rename a msg-accepted request, because the entry
  237. * in the space is being renamed.
  238. * Conditions:
  239. * The space is write-locked and active.
  240. */
  241. void
  242. ipc_marequest_rename(
  243. ipc_space_t space,
  244. mach_port_t old,
  245. mach_port_t new)
  246. {
  247. ipc_marequest_bucket_t bucket;
  248. ipc_marequest_t marequest, *last;
  249. assert(space->is_active);
  250. bucket = &ipc_marequest_table[IMAR_HASH(space, old)];
  251. imarb_lock(bucket);
  252. for (last = &bucket->imarb_head;
  253. (marequest = *last) != IMAR_NULL;
  254. last = &marequest->imar_next)
  255. if ((marequest->imar_space == space) &&
  256. (marequest->imar_name == old))
  257. break;
  258. assert(marequest != IMAR_NULL);
  259. *last = marequest->imar_next;
  260. imarb_unlock(bucket);
  261. marequest->imar_name = new;
  262. bucket = &ipc_marequest_table[IMAR_HASH(space, new)];
  263. imarb_lock(bucket);
  264. marequest->imar_next = bucket->imarb_head;
  265. bucket->imarb_head = marequest;
  266. imarb_unlock(bucket);
  267. }
  268. /*
  269. * Routine: ipc_marequest_destroy
  270. * Purpose:
  271. * Destroy a msg-accepted request, because
  272. * the kernel message is being received/destroyed.
  273. * Conditions:
  274. * Nothing locked.
  275. */
  276. void
  277. ipc_marequest_destroy(ipc_marequest_t marequest)
  278. {
  279. ipc_space_t space = marequest->imar_space;
  280. mach_port_t name;
  281. ipc_port_t soright;
  282. is_write_lock(space);
  283. name = marequest->imar_name;
  284. soright = marequest->imar_soright;
  285. if (name != MACH_PORT_NULL) {
  286. ipc_marequest_bucket_t bucket;
  287. ipc_marequest_t this, *last;
  288. bucket = &ipc_marequest_table[IMAR_HASH(space, name)];
  289. imarb_lock(bucket);
  290. for (last = &bucket->imarb_head;
  291. (this = *last) != IMAR_NULL;
  292. last = &this->imar_next)
  293. if ((this->imar_space == space) &&
  294. (this->imar_name == name))
  295. break;
  296. assert(this == marequest);
  297. *last = this->imar_next;
  298. imarb_unlock(bucket);
  299. if (space->is_active) {
  300. ipc_entry_t entry;
  301. entry = ipc_entry_lookup(space, name);
  302. assert(entry != IE_NULL);
  303. assert(entry->ie_bits & IE_BITS_MAREQUEST);
  304. assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
  305. entry->ie_bits &= ~IE_BITS_MAREQUEST;
  306. } else
  307. name = MACH_PORT_NULL;
  308. }
  309. is_write_unlock(space);
  310. is_release(space);
  311. imar_free(marequest);
  312. assert(soright != IP_NULL);
  313. ipc_notify_msg_accepted(soright, name);
  314. }
  315. #if MACH_IPC_DEBUG
  316. /*
  317. * Routine: ipc_marequest_info
  318. * Purpose:
  319. * Return information about the marequest hash table.
  320. * Fills the buffer with as much information as possible
  321. * and returns the desired size of the buffer.
  322. * Conditions:
  323. * Nothing locked. The caller should provide
  324. * possibly-pageable memory.
  325. */
  326. unsigned int
  327. ipc_marequest_info(
  328. unsigned int *maxp,
  329. hash_info_bucket_t *info,
  330. unsigned int count)
  331. {
  332. ipc_marequest_index_t i;
  333. if (ipc_marequest_size < count)
  334. count = ipc_marequest_size;
  335. for (i = 0; i < count; i++) {
  336. ipc_marequest_bucket_t bucket = &ipc_marequest_table[i];
  337. unsigned int bucket_count = 0;
  338. ipc_marequest_t marequest;
  339. imarb_lock(bucket);
  340. for (marequest = bucket->imarb_head;
  341. marequest != IMAR_NULL;
  342. marequest = marequest->imar_next)
  343. bucket_count++;
  344. imarb_unlock(bucket);
  345. /* don't touch pageable memory while holding locks */
  346. info[i].hib_count = bucket_count;
  347. }
  348. *maxp = (unsigned int)-1;
  349. return ipc_marequest_size;
  350. }
  351. #endif /* MACH_IPC_DEBUG */