ipc_port.c 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294
  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_port.c
  31. * Author: Rich Draves
  32. * Date: 1989
  33. *
  34. * Functions to manipulate IPC ports.
  35. */
  36. #pragma GCC diagnostic error "-Wundef"
  37. #include <glue/gnulinux.h>
  38. #include <kern/printf.h>
  39. #include <string.h>
  40. #include <mach/port.h>
  41. #include <mach/kern_return.h>
  42. #include <kern/lock.h>
  43. #include <kern/ipc_sched.h>
  44. #include <kern/ipc_kobject.h>
  45. #include <ipc/ipc_entry.h>
  46. #include <ipc/ipc_space.h>
  47. #include <ipc/ipc_object.h>
  48. #include <ipc/ipc_port.h>
  49. #include <ipc/ipc_pset.h>
  50. #include <ipc/ipc_thread.h>
  51. #include <ipc/ipc_mqueue.h>
  52. #include <ipc/ipc_notify.h>
  53. #if MACH_KDB
  54. #include <ddb/db_output.h>
  55. #include <ipc/ipc_print.h>
  56. #endif /* MACH_KDB */
  57. decl_simple_lock_data(, ipc_port_multiple_lock_data)
  58. decl_simple_lock_data(, ipc_port_timestamp_lock_data)
  59. ipc_port_timestamp_t ipc_port_timestamp_data;
  60. /*
  61. * Routine: ipc_port_timestamp
  62. * Purpose:
  63. * Retrieve a timestamp value.
  64. */
  65. ipc_port_timestamp_t
  66. ipc_port_timestamp(void)
  67. {
  68. ipc_port_timestamp_t timestamp;
  69. ipc_port_timestamp_lock();
  70. timestamp = ipc_port_timestamp_data++;
  71. ipc_port_timestamp_unlock();
  72. return timestamp;
  73. }
  74. /*
  75. * Routine: ipc_port_dnrequest
  76. * Purpose:
  77. * Try to allocate a dead-name request slot.
  78. * If successful, returns the request index.
  79. * Otherwise returns zero.
  80. * Conditions:
  81. * The port is locked and active.
  82. * Returns:
  83. * KERN_SUCCESS A request index was found.
  84. * KERN_NO_SPACE No index allocated.
  85. */
  86. kern_return_t
  87. ipc_port_dnrequest(
  88. ipc_port_t port,
  89. mach_port_t name,
  90. ipc_port_t soright,
  91. ipc_port_request_index_t *indexp)
  92. {
  93. ipc_port_request_t ipr, table;
  94. ipc_port_request_index_t index;
  95. assert(ip_active(port));
  96. assert(name != MACH_PORT_NULL);
  97. assert(soright != IP_NULL);
  98. table = port->ip_dnrequests;
  99. if (table == IPR_NULL)
  100. return KERN_NO_SPACE;
  101. index = table->ipr_next;
  102. if (index == 0)
  103. return KERN_NO_SPACE;
  104. ipr = &table[index];
  105. assert(ipr->ipr_name == MACH_PORT_NULL);
  106. table->ipr_next = ipr->ipr_next;
  107. ipr->ipr_name = name;
  108. ipr->ipr_soright = soright;
  109. *indexp = index;
  110. return KERN_SUCCESS;
  111. }
  112. /*
  113. * Routine: ipc_port_dngrow
  114. * Purpose:
  115. * Grow a port's table of dead-name requests.
  116. * Conditions:
  117. * The port must be locked and active.
  118. * Nothing else locked; will allocate memory.
  119. * Upon return the port is unlocked.
  120. * Returns:
  121. * KERN_SUCCESS Grew the table.
  122. * KERN_SUCCESS Somebody else grew the table.
  123. * KERN_SUCCESS The port died.
  124. * KERN_RESOURCE_SHORTAGE Couldn't allocate new table.
  125. */
  126. kern_return_t
  127. ipc_port_dngrow(ipc_port_t port)
  128. {
  129. ipc_table_size_t its;
  130. ipc_port_request_t otable, ntable;
  131. assert(ip_active(port));
  132. otable = port->ip_dnrequests;
  133. if (otable == IPR_NULL)
  134. its = &ipc_table_dnrequests[0];
  135. else
  136. its = otable->ipr_size + 1;
  137. ip_reference(port);
  138. ip_unlock(port);
  139. if ((its->its_size == 0) ||
  140. ((ntable = it_dnrequests_alloc(its)) == IPR_NULL)) {
  141. ipc_port_release(port);
  142. return KERN_RESOURCE_SHORTAGE;
  143. }
  144. ip_lock(port);
  145. ip_release(port);
  146. /*
  147. * Check that port is still active and that nobody else
  148. * has slipped in and grown the table on us. Note that
  149. * just checking port->ip_dnrequests == otable isn't
  150. * sufficient; must check ipr_size.
  151. */
  152. if (ip_active(port) &&
  153. (port->ip_dnrequests == otable) &&
  154. ((otable == IPR_NULL) || (otable->ipr_size+1 == its))) {
  155. ipc_table_size_t oits = 0; /* '=0' to shut up lint */
  156. ipc_table_elems_t osize, nsize;
  157. ipc_port_request_index_t free, i;
  158. /* copy old table to new table */
  159. if (otable != IPR_NULL) {
  160. oits = otable->ipr_size;
  161. osize = oits->its_size;
  162. free = otable->ipr_next;
  163. memcpy((ntable + 1), (otable + 1),
  164. (osize - 1) * sizeof(struct ipc_port_request));
  165. } else {
  166. osize = 1;
  167. free = 0;
  168. }
  169. nsize = its->its_size;
  170. assert(nsize > osize);
  171. /* add new elements to the new table's free list */
  172. for (i = osize; i < nsize; i++) {
  173. ipc_port_request_t ipr = &ntable[i];
  174. ipr->ipr_name = MACH_PORT_NULL;
  175. ipr->ipr_next = free;
  176. free = i;
  177. }
  178. ntable->ipr_next = free;
  179. ntable->ipr_size = its;
  180. port->ip_dnrequests = ntable;
  181. ip_unlock(port);
  182. if (otable != IPR_NULL)
  183. it_dnrequests_free(oits, otable);
  184. } else {
  185. ip_check_unlock(port);
  186. it_dnrequests_free(its, ntable);
  187. }
  188. return KERN_SUCCESS;
  189. }
  190. /*
  191. * Routine: ipc_port_dncancel
  192. * Purpose:
  193. * Cancel a dead-name request and return the send-once right.
  194. * Conditions:
  195. * The port must locked and active.
  196. */
  197. ipc_port_t
  198. ipc_port_dncancel(
  199. ipc_port_t port,
  200. mach_port_t name,
  201. ipc_port_request_index_t index)
  202. {
  203. ipc_port_request_t ipr, table;
  204. ipc_port_t dnrequest;
  205. assert(ip_active(port));
  206. assert(name != MACH_PORT_NULL);
  207. assert(index != 0);
  208. table = port->ip_dnrequests;
  209. assert(table != IPR_NULL);
  210. ipr = &table[index];
  211. dnrequest = ipr->ipr_soright;
  212. assert(ipr->ipr_name == name);
  213. /* return ipr to the free list inside the table */
  214. ipr->ipr_name = MACH_PORT_NULL;
  215. ipr->ipr_next = table->ipr_next;
  216. table->ipr_next = index;
  217. return dnrequest;
  218. }
  219. /*
  220. * Routine: ipc_port_pdrequest
  221. * Purpose:
  222. * Make a port-deleted request, returning the
  223. * previously registered send-once right.
  224. * Just cancels the previous request if notify is IP_NULL.
  225. * Conditions:
  226. * The port is locked and active. It is unlocked.
  227. * Consumes a ref for notify (if non-null), and
  228. * returns previous with a ref (if non-null).
  229. */
  230. void
  231. ipc_port_pdrequest(
  232. ipc_port_t port,
  233. const ipc_port_t notify,
  234. ipc_port_t *previousp)
  235. {
  236. ipc_port_t previous;
  237. assert(ip_active(port));
  238. previous = port->ip_pdrequest;
  239. port->ip_pdrequest = notify;
  240. ip_unlock(port);
  241. *previousp = previous;
  242. }
  243. /*
  244. * Routine: ipc_port_nsrequest
  245. * Purpose:
  246. * Make a no-senders request, returning the
  247. * previously registered send-once right.
  248. * Just cancels the previous request if notify is IP_NULL.
  249. * Conditions:
  250. * The port is locked and active. It is unlocked.
  251. * Consumes a ref for notify (if non-null), and
  252. * returns previous with a ref (if non-null).
  253. */
  254. void
  255. ipc_port_nsrequest(
  256. ipc_port_t port,
  257. mach_port_mscount_t sync,
  258. ipc_port_t notify,
  259. ipc_port_t *previousp)
  260. {
  261. ipc_port_t previous;
  262. mach_port_mscount_t mscount;
  263. assert(ip_active(port));
  264. previous = port->ip_nsrequest;
  265. mscount = port->ip_mscount;
  266. if ((port->ip_srights == 0) &&
  267. (sync <= mscount) &&
  268. (notify != IP_NULL)) {
  269. port->ip_nsrequest = IP_NULL;
  270. ip_unlock(port);
  271. ipc_notify_no_senders(notify, mscount);
  272. } else {
  273. port->ip_nsrequest = notify;
  274. ip_unlock(port);
  275. }
  276. *previousp = previous;
  277. }
  278. /*
  279. * Routine: ipc_port_set_qlimit
  280. * Purpose:
  281. * Changes a port's queue limit; the maximum number
  282. * of messages which may be queued to the port.
  283. * Conditions:
  284. * The port is locked and active.
  285. */
  286. void
  287. ipc_port_set_qlimit(
  288. ipc_port_t port,
  289. mach_port_msgcount_t qlimit)
  290. {
  291. assert(ip_active(port));
  292. /* wake up senders allowed by the new qlimit */
  293. if (qlimit > port->ip_qlimit) {
  294. mach_port_msgcount_t i, wakeup;
  295. /* caution: wakeup, qlimit are unsigned */
  296. wakeup = qlimit - port->ip_qlimit;
  297. for (i = 0; i < wakeup; i++) {
  298. ipc_thread_t th;
  299. th = ipc_thread_dequeue(&port->ip_blocked);
  300. if (th == ITH_NULL)
  301. break;
  302. th->ith_state = MACH_MSG_SUCCESS;
  303. thread_go(th);
  304. }
  305. }
  306. port->ip_qlimit = qlimit;
  307. }
  308. /*
  309. * Routine: ipc_port_lock_mqueue
  310. * Purpose:
  311. * Locks and returns the message queue that the port is using.
  312. * The message queue may be in the port or in its port set.
  313. * Conditions:
  314. * The port is locked and active.
  315. * Port set, message queue locks may be taken.
  316. */
  317. ipc_mqueue_t
  318. ipc_port_lock_mqueue(ipc_port_t port)
  319. {
  320. if (port->ip_pset != IPS_NULL) {
  321. ipc_pset_t pset = port->ip_pset;
  322. ips_lock(pset);
  323. if (ips_active(pset)) {
  324. imq_lock(&pset->ips_messages);
  325. ips_unlock(pset);
  326. return &pset->ips_messages;
  327. }
  328. ipc_pset_remove(pset, port);
  329. ips_check_unlock(pset);
  330. }
  331. imq_lock(&port->ip_messages);
  332. return &port->ip_messages;
  333. }
  334. /*
  335. * Routine: ipc_port_set_seqno
  336. * Purpose:
  337. * Changes a port's sequence number.
  338. * Conditions:
  339. * The port is locked and active.
  340. * Port set, message queue locks may be taken.
  341. */
  342. void
  343. ipc_port_set_seqno(
  344. ipc_port_t port,
  345. mach_port_seqno_t seqno)
  346. {
  347. ipc_mqueue_t mqueue;
  348. mqueue = ipc_port_lock_mqueue(port);
  349. port->ip_seqno = seqno;
  350. imq_unlock(mqueue);
  351. }
  352. /*
  353. * Routine: ipc_port_set_protected_payload
  354. * Purpose:
  355. * Changes a port's protected payload.
  356. * Conditions:
  357. * The port is locked and active.
  358. */
  359. void
  360. ipc_port_set_protected_payload(ipc_port_t port, unsigned long payload)
  361. {
  362. ipc_mqueue_t mqueue;
  363. mqueue = ipc_port_lock_mqueue(port);
  364. port->ip_protected_payload = payload;
  365. ipc_port_flag_protected_payload_set(port);
  366. imq_unlock(mqueue);
  367. }
  368. /*
  369. * Routine: ipc_port_clear_protected_payload
  370. * Purpose:
  371. * Clear a port's protected payload.
  372. * Conditions:
  373. * The port is locked and active.
  374. */
  375. void
  376. ipc_port_clear_protected_payload(ipc_port_t port)
  377. {
  378. ipc_mqueue_t mqueue;
  379. mqueue = ipc_port_lock_mqueue(port);
  380. ipc_port_flag_protected_payload_clear(port);
  381. imq_unlock(mqueue);
  382. }
  383. /*
  384. * Routine: ipc_port_clear_receiver
  385. * Purpose:
  386. * Prepares a receive right for transmission/destruction.
  387. * Conditions:
  388. * The port is locked and active.
  389. */
  390. void
  391. ipc_port_clear_receiver(
  392. ipc_port_t port)
  393. {
  394. ipc_pset_t pset;
  395. assert(ip_active(port));
  396. pset = port->ip_pset;
  397. if (pset != IPS_NULL) {
  398. /* No threads receiving from port, but must remove from set. */
  399. ips_lock(pset);
  400. ipc_pset_remove(pset, port);
  401. ips_check_unlock(pset);
  402. } else {
  403. /* Else, wake up all receivers, indicating why. */
  404. imq_lock(&port->ip_messages);
  405. ipc_mqueue_changed(&port->ip_messages, MACH_RCV_PORT_DIED);
  406. imq_unlock(&port->ip_messages);
  407. }
  408. ipc_port_set_mscount(port, 0);
  409. imq_lock(&port->ip_messages);
  410. port->ip_seqno = 0;
  411. imq_unlock(&port->ip_messages);
  412. }
  413. /*
  414. * Routine: ipc_port_init
  415. * Purpose:
  416. * Initializes a newly-allocated port.
  417. * Doesn't touch the ip_object fields.
  418. */
  419. void
  420. ipc_port_init(
  421. ipc_port_t port,
  422. ipc_space_t space,
  423. mach_port_t name)
  424. {
  425. /* port->ip_kobject doesn't have to be initialized */
  426. ipc_target_init(&port->ip_target, name);
  427. port->ip_receiver = space;
  428. port->ip_mscount = 0;
  429. port->ip_srights = 0;
  430. port->ip_sorights = 0;
  431. port->ip_nsrequest = IP_NULL;
  432. port->ip_pdrequest = IP_NULL;
  433. port->ip_dnrequests = IPR_NULL;
  434. port->ip_pset = IPS_NULL;
  435. port->ip_cur_target = &port->ip_target;
  436. port->ip_seqno = 0;
  437. port->ip_msgcount = 0;
  438. port->ip_qlimit = MACH_PORT_QLIMIT_DEFAULT;
  439. ipc_port_flag_protected_payload_clear(port);
  440. port->ip_protected_payload = 0;
  441. ipc_mqueue_init(&port->ip_messages);
  442. ipc_thread_queue_init(&port->ip_blocked);
  443. }
  444. /*
  445. * Routine: ipc_port_alloc
  446. * Purpose:
  447. * Allocate a port.
  448. * Conditions:
  449. * Nothing locked. If successful, the port is returned
  450. * locked. (The caller doesn't have a reference.)
  451. * Returns:
  452. * KERN_SUCCESS The port is allocated.
  453. * KERN_INVALID_TASK The space is dead.
  454. * KERN_NO_SPACE No room for an entry in the space.
  455. * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
  456. */
  457. kern_return_t
  458. ipc_port_alloc(
  459. ipc_space_t space,
  460. mach_port_t *namep,
  461. ipc_port_t *portp)
  462. {
  463. ipc_port_t port;
  464. mach_port_t name;
  465. kern_return_t kr;
  466. kr = ipc_object_alloc(space, IOT_PORT,
  467. MACH_PORT_TYPE_RECEIVE, 0,
  468. &name, (ipc_object_t *) &port);
  469. if (kr != KERN_SUCCESS)
  470. return kr;
  471. /* port is locked */
  472. ipc_port_init(port, space, name);
  473. *namep = name;
  474. *portp = port;
  475. return KERN_SUCCESS;
  476. }
  477. /*
  478. * Routine: ipc_port_alloc_name
  479. * Purpose:
  480. * Allocate a port, with a specific name.
  481. * Conditions:
  482. * Nothing locked. If successful, the port is returned
  483. * locked. (The caller doesn't have a reference.)
  484. * Returns:
  485. * KERN_SUCCESS The port is allocated.
  486. * KERN_INVALID_TASK The space is dead.
  487. * KERN_NAME_EXISTS The name already denotes a right.
  488. * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
  489. */
  490. kern_return_t
  491. ipc_port_alloc_name(
  492. ipc_space_t space,
  493. mach_port_t name,
  494. ipc_port_t *portp)
  495. {
  496. ipc_port_t port;
  497. kern_return_t kr;
  498. kr = ipc_object_alloc_name(space, IOT_PORT,
  499. MACH_PORT_TYPE_RECEIVE, 0,
  500. name, (ipc_object_t *) &port);
  501. if (kr != KERN_SUCCESS)
  502. return kr;
  503. /* port is locked */
  504. ipc_port_init(port, space, name);
  505. *portp = port;
  506. return KERN_SUCCESS;
  507. }
  508. /*
  509. * Routine: ipc_port_destroy
  510. * Purpose:
  511. * Destroys a port. Cleans up queued messages.
  512. *
  513. * If the port has a backup, it doesn't get destroyed,
  514. * but is sent in a port-destroyed notification to the backup.
  515. * Conditions:
  516. * The port is locked and alive; nothing else locked.
  517. * The caller has a reference, which is consumed.
  518. * Afterwards, the port is unlocked and dead.
  519. */
  520. void
  521. ipc_port_destroy(
  522. ipc_port_t port)
  523. {
  524. ipc_port_t pdrequest, nsrequest;
  525. ipc_mqueue_t mqueue;
  526. ipc_kmsg_queue_t kmqueue;
  527. ipc_kmsg_t kmsg;
  528. ipc_thread_t sender;
  529. ipc_port_request_t dnrequests;
  530. assert(ip_active(port));
  531. /* port->ip_receiver_name is garbage */
  532. /* port->ip_receiver/port->ip_destination is garbage */
  533. assert(port->ip_pset == IPS_NULL);
  534. assert(port->ip_mscount == 0);
  535. assert(port->ip_seqno == 0);
  536. /* first check for a backup port */
  537. pdrequest = port->ip_pdrequest;
  538. if (pdrequest != IP_NULL) {
  539. /* we assume the ref for pdrequest */
  540. port->ip_pdrequest = IP_NULL;
  541. /* make port be in limbo */
  542. port->ip_receiver_name = MACH_PORT_NULL;
  543. port->ip_destination = IP_NULL;
  544. ipc_port_flag_protected_payload_clear(port);
  545. ip_unlock(port);
  546. if (!ipc_port_check_circularity(port, pdrequest)) {
  547. /* consumes our refs for port and pdrequest */
  548. ipc_notify_port_destroyed(pdrequest, port);
  549. return;
  550. } else {
  551. /* consume pdrequest and destroy port */
  552. ipc_port_release_sonce(pdrequest);
  553. }
  554. ip_lock(port);
  555. assert(ip_active(port));
  556. assert(port->ip_pset == IPS_NULL);
  557. assert(port->ip_mscount == 0);
  558. assert(port->ip_seqno == 0);
  559. assert(port->ip_pdrequest == IP_NULL);
  560. assert(port->ip_receiver_name == MACH_PORT_NULL);
  561. assert(port->ip_destination == IP_NULL);
  562. /* fall through and destroy the port */
  563. }
  564. /*
  565. * rouse all blocked senders
  566. *
  567. * This must be done with the port locked, because
  568. * ipc_mqueue_send can play with the ip_blocked queue
  569. * of a dead port.
  570. */
  571. while ((sender = ipc_thread_dequeue(&port->ip_blocked)) != ITH_NULL) {
  572. sender->ith_state = MACH_MSG_SUCCESS;
  573. thread_go(sender);
  574. }
  575. /* once port is dead, we don't need to keep it locked */
  576. port->ip_object.io_bits &= ~IO_BITS_ACTIVE;
  577. port->ip_timestamp = ipc_port_timestamp();
  578. ip_unlock(port);
  579. /* throw away no-senders request */
  580. nsrequest = port->ip_nsrequest;
  581. if (nsrequest != IP_NULL)
  582. ipc_notify_send_once(nsrequest); /* consumes ref */
  583. /* destroy any queued messages */
  584. mqueue = &port->ip_messages;
  585. imq_lock(mqueue);
  586. assert(ipc_thread_queue_empty(&mqueue->imq_threads));
  587. kmqueue = &mqueue->imq_messages;
  588. while ((kmsg = ipc_kmsg_dequeue(kmqueue)) != IKM_NULL) {
  589. imq_unlock(mqueue);
  590. assert(kmsg->ikm_header.msgh_remote_port ==
  591. (mach_port_t) port);
  592. ipc_port_release(port);
  593. kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL;
  594. ipc_kmsg_destroy(kmsg);
  595. imq_lock(mqueue);
  596. }
  597. imq_unlock(mqueue);
  598. /* generate dead-name notifications */
  599. dnrequests = port->ip_dnrequests;
  600. if (dnrequests != IPR_NULL) {
  601. ipc_table_size_t its = dnrequests->ipr_size;
  602. ipc_table_elems_t size = its->its_size;
  603. ipc_port_request_index_t index;
  604. for (index = 1; index < size; index++) {
  605. ipc_port_request_t ipr = &dnrequests[index];
  606. mach_port_t name = ipr->ipr_name;
  607. ipc_port_t soright;
  608. if (name == MACH_PORT_NULL)
  609. continue;
  610. soright = ipr->ipr_soright;
  611. assert(soright != IP_NULL);
  612. ipc_notify_dead_name(soright, name);
  613. }
  614. it_dnrequests_free(its, dnrequests);
  615. }
  616. if (ip_kotype(port) != IKOT_NONE)
  617. ipc_kobject_destroy(port);
  618. /* Common destruction for the IPC target. */
  619. ipc_target_terminate(&port->ip_target);
  620. ipc_port_release(port); /* consume caller's ref */
  621. }
  622. /*
  623. * Routine: ipc_port_check_circularity
  624. * Purpose:
  625. * Check if queueing "port" in a message for "dest"
  626. * would create a circular group of ports and messages.
  627. *
  628. * If no circularity (FALSE returned), then "port"
  629. * is changed from "in limbo" to "in transit".
  630. *
  631. * That is, we want to set port->ip_destination == dest,
  632. * but guaranteeing that this doesn't create a circle
  633. * port->ip_destination->ip_destination->... == port
  634. * Conditions:
  635. * No ports locked. References held for "port" and "dest".
  636. */
  637. boolean_t
  638. ipc_port_check_circularity(
  639. ipc_port_t port,
  640. ipc_port_t dest)
  641. {
  642. ipc_port_t base;
  643. assert(port != IP_NULL);
  644. assert(dest != IP_NULL);
  645. if (port == dest)
  646. return TRUE;
  647. base = dest;
  648. /*
  649. * First try a quick check that can run in parallel.
  650. * No circularity if dest is not in transit.
  651. */
  652. ip_lock(port);
  653. if (ip_lock_try(dest)) {
  654. if (!ip_active(dest) ||
  655. (dest->ip_receiver_name != MACH_PORT_NULL) ||
  656. (dest->ip_destination == IP_NULL))
  657. goto not_circular;
  658. /* dest is in transit; further checking necessary */
  659. ip_unlock(dest);
  660. }
  661. ip_unlock(port);
  662. ipc_port_multiple_lock(); /* massive serialization */
  663. /*
  664. * Search for the end of the chain (a port not in transit),
  665. * acquiring locks along the way.
  666. */
  667. for (;;) {
  668. ip_lock(base);
  669. if (!ip_active(base) ||
  670. (base->ip_receiver_name != MACH_PORT_NULL) ||
  671. (base->ip_destination == IP_NULL))
  672. break;
  673. base = base->ip_destination;
  674. }
  675. /* all ports in chain from dest to base, inclusive, are locked */
  676. if (port == base) {
  677. /* circularity detected! */
  678. ipc_port_multiple_unlock();
  679. /* port (== base) is in limbo */
  680. assert(ip_active(port));
  681. assert(port->ip_receiver_name == MACH_PORT_NULL);
  682. assert(port->ip_destination == IP_NULL);
  683. while (dest != IP_NULL) {
  684. ipc_port_t next;
  685. /* dest is in transit or in limbo */
  686. assert(ip_active(dest));
  687. assert(dest->ip_receiver_name == MACH_PORT_NULL);
  688. next = dest->ip_destination;
  689. ip_unlock(dest);
  690. dest = next;
  691. }
  692. return TRUE;
  693. }
  694. /*
  695. * The guarantee: lock port while the entire chain is locked.
  696. * Once port is locked, we can take a reference to dest,
  697. * add port to the chain, and unlock everything.
  698. */
  699. ip_lock(port);
  700. ipc_port_multiple_unlock();
  701. not_circular:
  702. /* port is in limbo */
  703. assert(ip_active(port));
  704. assert(port->ip_receiver_name == MACH_PORT_NULL);
  705. assert(port->ip_destination == IP_NULL);
  706. ip_reference(dest);
  707. port->ip_destination = dest;
  708. /* now unlock chain */
  709. while (port != base) {
  710. ipc_port_t next;
  711. /* port is in transit */
  712. assert(ip_active(port));
  713. assert(port->ip_receiver_name == MACH_PORT_NULL);
  714. assert(port->ip_destination != IP_NULL);
  715. next = port->ip_destination;
  716. ip_unlock(port);
  717. port = next;
  718. }
  719. /* base is not in transit */
  720. assert(!ip_active(base) ||
  721. (base->ip_receiver_name != MACH_PORT_NULL) ||
  722. (base->ip_destination == IP_NULL));
  723. ip_unlock(base);
  724. return FALSE;
  725. }
  726. /*
  727. * Routine: ipc_port_lookup_notify
  728. * Purpose:
  729. * Make a send-once notify port from a receive right.
  730. * Returns IP_NULL if name doesn't denote a receive right.
  731. * Conditions:
  732. * The space must be locked (read or write) and active.
  733. */
  734. ipc_port_t
  735. ipc_port_lookup_notify(
  736. ipc_space_t space,
  737. mach_port_t name)
  738. {
  739. ipc_port_t port;
  740. ipc_entry_t entry;
  741. assert(space->is_active);
  742. entry = ipc_entry_lookup(space, name);
  743. if (entry == IE_NULL)
  744. return IP_NULL;
  745. if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)
  746. return IP_NULL;
  747. port = (ipc_port_t) entry->ie_object;
  748. assert(port != IP_NULL);
  749. ip_lock(port);
  750. assert(ip_active(port));
  751. assert(port->ip_receiver_name == name);
  752. assert(port->ip_receiver == space);
  753. ip_reference(port);
  754. port->ip_sorights++;
  755. ip_unlock(port);
  756. return port;
  757. }
  758. /*
  759. * Routine: ipc_port_make_send
  760. * Purpose:
  761. * Make a naked send right from a receive right.
  762. * Conditions:
  763. * The port is not locked but it is active.
  764. */
  765. ipc_port_t
  766. ipc_port_make_send(
  767. ipc_port_t port)
  768. {
  769. assert(IP_VALID(port));
  770. ip_lock(port);
  771. assert(ip_active(port));
  772. port->ip_mscount++;
  773. port->ip_srights++;
  774. ip_reference(port);
  775. ip_unlock(port);
  776. return port;
  777. }
  778. /*
  779. * Routine: ipc_port_copy_send
  780. * Purpose:
  781. * Make a naked send right from another naked send right.
  782. * IP_NULL -> IP_NULL
  783. * IP_DEAD -> IP_DEAD
  784. * dead port -> IP_DEAD
  785. * live port -> port + ref
  786. * Conditions:
  787. * Nothing locked except possibly a space.
  788. */
  789. ipc_port_t
  790. ipc_port_copy_send(
  791. ipc_port_t port)
  792. {
  793. ipc_port_t sright;
  794. if (!IP_VALID(port))
  795. return port;
  796. ip_lock(port);
  797. if (ip_active(port)) {
  798. assert(port->ip_srights > 0);
  799. ip_reference(port);
  800. port->ip_srights++;
  801. sright = port;
  802. } else
  803. sright = IP_DEAD;
  804. ip_unlock(port);
  805. return sright;
  806. }
  807. /*
  808. * Routine: ipc_port_copyout_send
  809. * Purpose:
  810. * Copyout a naked send right (possibly null/dead),
  811. * or if that fails, destroy the right.
  812. * Conditions:
  813. * Nothing locked.
  814. */
  815. mach_port_t
  816. ipc_port_copyout_send(
  817. ipc_port_t sright,
  818. ipc_space_t space)
  819. {
  820. mach_port_t name;
  821. if (IP_VALID(sright)) {
  822. kern_return_t kr;
  823. kr = ipc_object_copyout(space, (ipc_object_t) sright,
  824. MACH_MSG_TYPE_PORT_SEND, TRUE, &name);
  825. if (kr != KERN_SUCCESS) {
  826. ipc_port_release_send(sright);
  827. if (kr == KERN_INVALID_CAPABILITY)
  828. name = MACH_PORT_DEAD;
  829. else
  830. name = MACH_PORT_NULL;
  831. }
  832. } else
  833. name = (mach_port_t) sright;
  834. return name;
  835. }
  836. /*
  837. * Routine: ipc_port_release_send
  838. * Purpose:
  839. * Release a (valid) naked send right.
  840. * Consumes a ref for the port.
  841. * Conditions:
  842. * Nothing locked.
  843. */
  844. void
  845. ipc_port_release_send(
  846. ipc_port_t port)
  847. {
  848. ipc_port_t nsrequest = IP_NULL;
  849. mach_port_mscount_t mscount;
  850. assert(IP_VALID(port));
  851. ip_lock(port);
  852. ip_release(port);
  853. if (!ip_active(port)) {
  854. ip_check_unlock(port);
  855. return;
  856. }
  857. assert(port->ip_srights > 0);
  858. if (--port->ip_srights == 0) {
  859. nsrequest = port->ip_nsrequest;
  860. if (nsrequest != IP_NULL) {
  861. port->ip_nsrequest = IP_NULL;
  862. mscount = port->ip_mscount;
  863. }
  864. }
  865. ip_unlock(port);
  866. if (nsrequest != IP_NULL)
  867. ipc_notify_no_senders(nsrequest, mscount);
  868. }
  869. /*
  870. * Routine: ipc_port_make_sonce
  871. * Purpose:
  872. * Make a naked send-once right from a receive right.
  873. * Conditions:
  874. * The port is not locked but it is active.
  875. */
  876. ipc_port_t
  877. ipc_port_make_sonce(
  878. ipc_port_t port)
  879. {
  880. assert(IP_VALID(port));
  881. ip_lock(port);
  882. assert(ip_active(port));
  883. port->ip_sorights++;
  884. ip_reference(port);
  885. ip_unlock(port);
  886. return port;
  887. }
  888. /*
  889. * Routine: ipc_port_release_sonce
  890. * Purpose:
  891. * Release a naked send-once right.
  892. * Consumes a ref for the port.
  893. *
  894. * In normal situations, this is never used.
  895. * Send-once rights are only consumed when
  896. * a message (possibly a send-once notification)
  897. * is sent to them.
  898. * Conditions:
  899. * Nothing locked except possibly a space.
  900. */
  901. void
  902. ipc_port_release_sonce(
  903. ipc_port_t port)
  904. {
  905. assert(IP_VALID(port));
  906. ip_lock(port);
  907. assert(port->ip_sorights > 0);
  908. port->ip_sorights--;
  909. ip_release(port);
  910. if (!ip_active(port)) {
  911. ip_check_unlock(port);
  912. return;
  913. }
  914. ip_unlock(port);
  915. }
  916. /*
  917. * Routine: ipc_port_release_receive
  918. * Purpose:
  919. * Release a naked (in limbo or in transit) receive right.
  920. * Consumes a ref for the port; destroys the port.
  921. * Conditions:
  922. * Nothing locked.
  923. */
  924. void
  925. ipc_port_release_receive(
  926. ipc_port_t port)
  927. {
  928. ipc_port_t dest;
  929. assert(IP_VALID(port));
  930. ip_lock(port);
  931. assert(ip_active(port));
  932. assert(port->ip_receiver_name == MACH_PORT_NULL);
  933. dest = port->ip_destination;
  934. ipc_port_destroy(port); /* consumes ref, unlocks */
  935. if (dest != IP_NULL)
  936. ipc_port_release(dest);
  937. }
  938. /*
  939. * Routine: ipc_port_alloc_special
  940. * Purpose:
  941. * Allocate a port in a special space.
  942. * The new port is returned with one ref.
  943. * If unsuccessful, IP_NULL is returned.
  944. * Conditions:
  945. * Nothing locked.
  946. */
  947. ipc_port_t
  948. ipc_port_alloc_special(ipc_space_t space)
  949. {
  950. ipc_port_t port;
  951. port = ip_alloc();
  952. if (port == IP_NULL)
  953. return IP_NULL;
  954. ip_lock_init(port);
  955. port->ip_references = 1;
  956. port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0);
  957. /*
  958. * The actual values of ip_receiver_name aren't important,
  959. * as long as they are valid (not null/dead).
  960. *
  961. * Mach4: we set it to the internal port structure address
  962. * so we can always just pass on ip_receiver_name during
  963. * an rpc regardless of whether the destination is user or
  964. * kernel (i.e. no special-casing code for the kernel along
  965. * the fast rpc path).
  966. */
  967. ipc_port_init(port, space, (mach_port_t)port);
  968. return port;
  969. }
  970. /*
  971. * Routine: ipc_port_dealloc_special
  972. * Purpose:
  973. * Deallocate a port in a special space.
  974. * Consumes one ref for the port.
  975. * Conditions:
  976. * Nothing locked.
  977. */
  978. void
  979. ipc_port_dealloc_special(
  980. ipc_port_t port,
  981. ipc_space_t space)
  982. {
  983. ip_lock(port);
  984. assert(ip_active(port));
  985. assert(port->ip_receiver_name != MACH_PORT_NULL);
  986. assert(port->ip_receiver == space);
  987. /*
  988. * We clear ip_receiver_name and ip_receiver to simplify
  989. * the ipc_space_kernel check in ipc_mqueue_send.
  990. */
  991. port->ip_receiver_name = MACH_PORT_NULL;
  992. port->ip_receiver = IS_NULL;
  993. /*
  994. * For ipc_space_kernel, all ipc_port_clear_receiver does
  995. * is clean things up for the assertions in ipc_port_destroy.
  996. * For ipc_space_reply, there might be a waiting receiver.
  997. */
  998. ipc_port_clear_receiver(port);
  999. ipc_port_destroy(port);
  1000. }
  1001. #if MACH_KDB
  1002. #define printf kdbprintf
  1003. /*
  1004. * Routine: ipc_port_print
  1005. * Purpose:
  1006. * Pretty-print a port for kdb.
  1007. */
  1008. void
  1009. ipc_port_print(port)
  1010. const ipc_port_t port;
  1011. {
  1012. printf("port 0x%x\n", port);
  1013. indent += 2;
  1014. iprintf("flags ");
  1015. printf("has_protected_payload=%d",
  1016. ipc_port_flag_protected_payload(port));
  1017. printf("\n");
  1018. ipc_object_print(&port->ip_object);
  1019. iprintf("receiver=0x%x", port->ip_receiver);
  1020. printf(", receiver_name=0x%x\n", port->ip_receiver_name);
  1021. iprintf("mscount=%d", port->ip_mscount);
  1022. printf(", srights=%d", port->ip_srights);
  1023. printf(", sorights=%d\n", port->ip_sorights);
  1024. iprintf("nsrequest=0x%x", port->ip_nsrequest);
  1025. printf(", pdrequest=0x%x", port->ip_pdrequest);
  1026. printf(", dnrequests=0x%x\n", port->ip_dnrequests);
  1027. iprintf("pset=0x%x", port->ip_pset);
  1028. printf(", seqno=%d", port->ip_seqno);
  1029. printf(", msgcount=%d", port->ip_msgcount);
  1030. printf(", qlimit=%d\n", port->ip_qlimit);
  1031. iprintf("kmsgs=0x%x", port->ip_messages.imq_messages.ikmq_base);
  1032. printf(", rcvrs=0x%x", port->ip_messages.imq_threads.ithq_base);
  1033. printf(", sndrs=0x%x", port->ip_blocked.ithq_base);
  1034. printf(", kobj=0x%x\n", port->ip_kobject);
  1035. iprintf("protected_payload=%p\n", (void *) port->ip_protected_payload);
  1036. indent -= 2;
  1037. }
  1038. #endif /* MACH_KDB */