dispatch_deadname.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /*
  2. * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
  3. *
  4. * @APPLE_APACHE_LICENSE_HEADER_START@
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * @APPLE_APACHE_LICENSE_HEADER_END@
  19. */
  20. #include <dispatch/dispatch.h>
  21. #include <dispatch/private.h>
  22. #ifdef __APPLE__
  23. #include <mach/mach.h>
  24. #endif
  25. #include <stdio.h>
  26. #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
  27. #include <unistd.h>
  28. #endif
  29. #include <stdlib.h>
  30. #include <assert.h>
  31. #include <bsdtests.h>
  32. #include "dispatch_test.h"
  33. #if TEST_MACHPORT_DEBUG
  34. #define test_mach_assume_zero(x) ({kern_return_t _kr = (x); \
  35. if (_kr) fprintf(stderr, "mach error 0x%x \"%s\": %s\n", \
  36. _kr, mach_error_string(_kr), #x); (void)kr; })
  37. void
  38. test_mach_debug_port(mach_port_t name, const char *str, unsigned int line)
  39. {
  40. mach_port_type_t type;
  41. mach_msg_bits_t ns = 0, nr = 0, nso = 0, nd = 0;
  42. unsigned int dnreqs = 0, dnrsiz;
  43. kern_return_t kr = mach_port_type(mach_task_self(), name, &type);
  44. if (kr) {
  45. fprintf(stderr, "machport[0x%08x] = { error(0x%x) \"%s\" }: %s %u\n",
  46. name, kr, mach_error_string(kr), str, line);
  47. return;
  48. }
  49. if (type & MACH_PORT_TYPE_SEND) {
  50. test_mach_assume_zero(mach_port_get_refs(mach_task_self(), name,
  51. MACH_PORT_RIGHT_SEND, &ns));
  52. }
  53. if (type & MACH_PORT_TYPE_SEND_ONCE) {
  54. test_mach_assume_zero(mach_port_get_refs(mach_task_self(), name,
  55. MACH_PORT_RIGHT_SEND_ONCE, &nso));
  56. }
  57. if (type & MACH_PORT_TYPE_DEAD_NAME) {
  58. test_mach_assume_zero(mach_port_get_refs(mach_task_self(), name,
  59. MACH_PORT_RIGHT_DEAD_NAME, &nd));
  60. }
  61. if (type & (MACH_PORT_TYPE_RECEIVE|MACH_PORT_TYPE_SEND)) {
  62. test_mach_assume_zero(mach_port_dnrequest_info(mach_task_self(), name,
  63. &dnrsiz, &dnreqs));
  64. }
  65. if (type & MACH_PORT_TYPE_RECEIVE) {
  66. mach_port_status_t status = { .mps_pset = 0, };
  67. mach_msg_type_number_t cnt = MACH_PORT_RECEIVE_STATUS_COUNT;
  68. test_mach_assume_zero(mach_port_get_refs(mach_task_self(), name,
  69. MACH_PORT_RIGHT_RECEIVE, &nr));
  70. test_mach_assume_zero(mach_port_get_attributes(mach_task_self(), name,
  71. MACH_PORT_RECEIVE_STATUS, (void*)&status, &cnt));
  72. fprintf(stderr, "machport[0x%08x] = { R(%03u) S(%03u) SO(%03u) D(%03u) "
  73. "dnreqs(%03u) spreq(%s) nsreq(%s) pdreq(%s) srights(%s) "
  74. "sorights(%03u) qlim(%03u) msgcount(%03u) mkscount(%03u) "
  75. "seqno(%03u) }: %s %u\n", name, nr, ns, nso, nd, dnreqs,
  76. type & MACH_PORT_TYPE_SPREQUEST ? "Y":"N",
  77. status.mps_nsrequest ? "Y":"N", status.mps_pdrequest ? "Y":"N",
  78. status.mps_srights ? "Y":"N", status.mps_sorights,
  79. status.mps_qlimit, status.mps_msgcount, status.mps_mscount,
  80. status.mps_seqno, str, line);
  81. } else if (type & (MACH_PORT_TYPE_SEND|MACH_PORT_TYPE_SEND_ONCE|
  82. MACH_PORT_TYPE_DEAD_NAME)) {
  83. fprintf(stderr, "machport[0x%08x] = { R(%03u) S(%03u) SO(%03u) D(%03u) "
  84. "dnreqs(%03u) spreq(%s) }: %s %u\n", name, nr, ns, nso, nd,
  85. dnreqs, type & MACH_PORT_TYPE_SPREQUEST ? "Y":"N", str, line);
  86. } else {
  87. fprintf(stderr, "machport[0x%08x] = { type(0x%08x) }: %s %u\n", name,
  88. type, str, line);
  89. }
  90. fflush(stderr);
  91. }
  92. #define test_mach_debug_port(x) test_mach_debug_port(x, __func__, __LINE__)
  93. #else
  94. #define test_mach_debug_port(x) (void)(x)
  95. #endif
  96. static dispatch_group_t g;
  97. static volatile long sent, received;
  98. void
  99. test_dead_name(void)
  100. {
  101. dispatch_group_enter(g);
  102. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  103. dispatch_source_t ds0;
  104. kern_return_t kr;
  105. mach_port_t mp = pthread_mach_thread_np(pthread_self());
  106. assert(mp);
  107. kr = mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_SEND, 1);
  108. test_mach_error("mach_port_mod_refs", kr, KERN_SUCCESS);
  109. ds0 = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, mp,
  110. DISPATCH_MACH_SEND_DEAD, dispatch_get_main_queue());
  111. test_ptr_notnull("DISPATCH_SOURCE_TYPE_MACH_SEND", ds0);
  112. dispatch_source_set_event_handler(ds0, ^{
  113. test_long("DISPATCH_MACH_SEND_DEAD",
  114. dispatch_source_get_handle(ds0), mp);
  115. dispatch_source_cancel(ds0);
  116. });
  117. dispatch_source_set_cancel_handler(ds0, ^{
  118. kern_return_t kr = mach_port_deallocate(mach_task_self(), mp);
  119. test_mach_error("mach_port_deallocate", kr, KERN_SUCCESS);
  120. dispatch_release(ds0);
  121. dispatch_group_leave(g);
  122. });
  123. dispatch_resume(ds0);
  124. // give the mgr queue time to start, otherwise the mgr queue will run
  125. // on this thread, thus defeating the test which assumes that this
  126. // thread will die.
  127. usleep(100000);
  128. });
  129. dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
  130. }
  131. void
  132. test_register_already_dead_name(void)
  133. {
  134. dispatch_source_t ds0;
  135. kern_return_t kr;
  136. mach_port_t mp;
  137. dispatch_group_enter(g);
  138. kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
  139. test_mach_error("mach_port_allocate", kr, KERN_SUCCESS);
  140. kr = mach_port_insert_right(mach_task_self(), mp, mp,
  141. MACH_MSG_TYPE_MAKE_SEND);
  142. test_mach_error("mach_port_insert_right", kr, KERN_SUCCESS);
  143. kr = mach_port_mod_refs(mach_task_self(), mp,
  144. MACH_PORT_RIGHT_RECEIVE, -1); // turn send right into dead name
  145. test_mach_error("mach_port_mod_refs", kr, KERN_SUCCESS);
  146. ds0 = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, mp,
  147. DISPATCH_MACH_SEND_DEAD, dispatch_get_global_queue(0, 0));
  148. dispatch_source_set_event_handler(ds0, ^{
  149. test_long("DISPATCH_MACH_SEND_DEAD",
  150. dispatch_source_get_handle(ds0), mp);
  151. dispatch_source_cancel(ds0);
  152. dispatch_release(ds0);
  153. });
  154. dispatch_source_set_cancel_handler(ds0, ^{
  155. kern_return_t kr = mach_port_deallocate(mach_task_self(), mp);
  156. test_mach_error("mach_port_deallocate", kr, KERN_SUCCESS);
  157. dispatch_group_leave(g);
  158. });
  159. dispatch_resume(ds0);
  160. dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
  161. }
  162. void
  163. test_receive_and_dead_name(void)
  164. {
  165. dispatch_source_t ds0, ds;
  166. kern_return_t kr;
  167. mach_port_t mp;
  168. received = 0;
  169. dispatch_group_enter(g);
  170. kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
  171. test_mach_error("mach_port_allocate", kr, KERN_SUCCESS);
  172. kr = mach_port_insert_right(mach_task_self(), mp, mp,
  173. MACH_MSG_TYPE_MAKE_SEND);
  174. test_mach_error("mach_port_insert_right", kr, KERN_SUCCESS);
  175. ds0 = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, mp,
  176. DISPATCH_MACH_SEND_DEAD, dispatch_get_global_queue(0, 0));
  177. dispatch_source_set_event_handler(ds0, ^{
  178. test_long("DISPATCH_MACH_SEND_DEAD",
  179. dispatch_source_get_handle(ds0), mp);
  180. dispatch_source_cancel(ds0);
  181. dispatch_release(ds0);
  182. });
  183. dispatch_source_set_cancel_handler(ds0, ^{
  184. kern_return_t kr = mach_port_deallocate(mach_task_self(), mp);
  185. test_mach_error("mach_port_deallocate", kr, KERN_SUCCESS);
  186. dispatch_group_leave(g);
  187. });
  188. dispatch_resume(ds0);
  189. ds = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0,
  190. dispatch_get_global_queue(0, 0));
  191. dispatch_source_set_event_handler(ds, ^{
  192. __sync_add_and_fetch(&received, 1);
  193. usleep(100000); // rdar://problem/7676437 race with send source re-arm
  194. mach_msg_empty_rcv_t msg = { .header = {
  195. .msgh_size = sizeof(mach_msg_empty_rcv_t),
  196. .msgh_local_port = mp,
  197. }};
  198. kern_return_t kr = mach_msg_receive(&msg.header);
  199. test_mach_error("mach_msg_receive", kr, KERN_SUCCESS);
  200. });
  201. dispatch_source_set_cancel_handler(ds, ^{
  202. kern_return_t kr = mach_port_mod_refs(mach_task_self(), mp,
  203. MACH_PORT_RIGHT_RECEIVE, -1); // turns send right into dead name
  204. test_mach_error("mach_port_mod_refs", kr, KERN_SUCCESS);
  205. });
  206. dispatch_resume(ds);
  207. mach_msg_empty_send_t msg = { .header = {
  208. .msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND),
  209. .msgh_size = sizeof(mach_msg_empty_send_t),
  210. .msgh_remote_port = mp,
  211. }};
  212. kr = mach_msg_send(&msg.header);
  213. test_mach_error("mach_msg_send", kr, KERN_SUCCESS);
  214. usleep(200000);
  215. dispatch_source_cancel(ds);
  216. dispatch_release(ds);
  217. test_long("DISPATCH_SOURCE_TYPE_MACH_RECV", received, 1);
  218. if (received > 1 ) {
  219. test_stop();
  220. }
  221. dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
  222. }
  223. #if DISPATCH_API_VERSION >= 20110201 && defined(MACH_NOTIFY_SEND_POSSIBLE) && \
  224. defined(MACH_SEND_NOTIFY)
  225. #define TEST_SP_MSGCOUNT 11 // (2*qlim)+1
  226. static bool
  227. send_until_timeout(mach_port_t mp)
  228. {
  229. kern_return_t kr;
  230. do {
  231. test_mach_debug_port(mp);
  232. mach_msg_empty_send_t msg = { .header = {
  233. .msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND),
  234. .msgh_size = sizeof(mach_msg_empty_send_t),
  235. .msgh_remote_port = mp,
  236. }};
  237. kr = mach_msg(&msg.header,
  238. MACH_SEND_MSG|MACH_SEND_NOTIFY|MACH_SEND_TIMEOUT,
  239. msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
  240. MACH_PORT_NULL);
  241. if (kr == MACH_SEND_TIMED_OUT) {
  242. mach_msg_destroy(&msg.header);
  243. test_mach_error("mach_msg(MACH_SEND_MSG) timed out", kr,
  244. MACH_SEND_TIMED_OUT);
  245. } else {
  246. test_mach_error("mach_msg(MACH_SEND_MSG)", kr, KERN_SUCCESS);
  247. if (kr) test_stop();
  248. }
  249. } while (!kr && __sync_add_and_fetch(&sent, 1) < TEST_SP_MSGCOUNT);
  250. test_mach_debug_port(mp);
  251. return kr;
  252. }
  253. void
  254. test_send_possible(void) // rdar://problem/8758200
  255. {
  256. dispatch_source_t ds0, ds, dsp;
  257. kern_return_t kr;
  258. mach_port_t mp;
  259. sent = 0;
  260. received = 0;
  261. dispatch_group_enter(g);
  262. kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
  263. test_mach_error("mach_port_allocate", kr, KERN_SUCCESS);
  264. test_mach_debug_port(mp);
  265. kr = mach_port_insert_right(mach_task_self(), mp, mp,
  266. MACH_MSG_TYPE_MAKE_SEND);
  267. test_mach_error("mach_port_insert_right", kr, KERN_SUCCESS);
  268. test_mach_debug_port(mp);
  269. ds0 = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, mp,
  270. DISPATCH_MACH_SEND_DEAD, dispatch_get_global_queue(0, 0));
  271. dispatch_source_set_registration_handler(ds0, ^{
  272. test_long("DISPATCH_MACH_SEND_DEAD registered",
  273. dispatch_source_get_handle(ds0), mp);
  274. test_mach_debug_port(mp);
  275. });
  276. dispatch_source_set_event_handler(ds0, ^{
  277. test_long("DISPATCH_MACH_SEND_DEAD delivered",
  278. dispatch_source_get_handle(ds0), mp);
  279. test_mach_debug_port(mp);
  280. dispatch_source_cancel(ds0);
  281. dispatch_release(ds0);
  282. });
  283. dispatch_source_set_cancel_handler(ds0, ^{
  284. test_long("DISPATCH_MACH_SEND_DEAD canceled",
  285. dispatch_source_get_handle(ds0), mp);
  286. test_mach_debug_port(mp);
  287. kern_return_t kr = mach_port_deallocate(mach_task_self(), mp);
  288. test_mach_error("mach_port_deallocate", kr, KERN_SUCCESS);
  289. test_mach_debug_port(mp);
  290. dispatch_group_leave(g);
  291. });
  292. dispatch_resume(ds0);
  293. ds = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0,
  294. dispatch_get_global_queue(0, 0));
  295. dispatch_source_set_registration_handler(ds, ^{
  296. test_long("DISPATCH_SOURCE_TYPE_MACH_RECV registered",
  297. dispatch_source_get_handle(ds), mp);
  298. test_mach_debug_port(mp);
  299. });
  300. dispatch_source_set_event_handler(ds, ^{
  301. test_long("DISPATCH_SOURCE_TYPE_MACH_RECV delivered",
  302. dispatch_source_get_handle(ds), mp);
  303. kern_return_t kr;
  304. do {
  305. test_mach_debug_port(mp);
  306. usleep(10000); // simulate slow receiver
  307. mach_msg_empty_rcv_t msg = { .header = {
  308. .msgh_size = sizeof(mach_msg_empty_rcv_t),
  309. .msgh_local_port = mp,
  310. }};
  311. kr = mach_msg(&msg.header,
  312. MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, msg.header.msgh_size,
  313. msg.header.msgh_local_port, MACH_MSG_TIMEOUT_NONE,
  314. MACH_PORT_NULL);
  315. if (kr == MACH_RCV_TIMED_OUT) {
  316. test_mach_error("mach_msg(MACH_RCV_MSG) timed out", kr,
  317. MACH_RCV_TIMED_OUT);
  318. } else {
  319. test_mach_error("mach_msg(MACH_RCV_MSG)", kr, KERN_SUCCESS);
  320. if (kr) test_stop();
  321. }
  322. } while (!kr && __sync_add_and_fetch(&received, 1));
  323. test_mach_debug_port(mp);
  324. });
  325. dispatch_source_set_cancel_handler(ds, ^{
  326. test_long("DISPATCH_SOURCE_TYPE_MACH_RECV canceled",
  327. dispatch_source_get_handle(ds), mp);
  328. test_mach_debug_port(mp);
  329. kern_return_t kr = mach_port_mod_refs(mach_task_self(), mp,
  330. MACH_PORT_RIGHT_RECEIVE, -1); // trigger dead name notification
  331. test_mach_error("mach_port_mod_refs", kr, KERN_SUCCESS);
  332. test_mach_debug_port(mp);
  333. });
  334. dispatch_resume(ds);
  335. dsp = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, mp,
  336. DISPATCH_MACH_SEND_POSSIBLE, dispatch_get_global_queue(0, 0));
  337. dispatch_source_set_registration_handler(dsp, ^{
  338. test_long("DISPATCH_MACH_SEND_POSSIBLE registered",
  339. dispatch_source_get_handle(dsp), mp);
  340. if (!send_until_timeout(mp)) {
  341. dispatch_source_cancel(dsp); // stop sending
  342. dispatch_release(dsp);
  343. }
  344. });
  345. dispatch_source_set_event_handler(dsp, ^{
  346. test_long("DISPATCH_MACH_SEND_POSSIBLE delivered",
  347. dispatch_source_get_handle(dsp), mp);
  348. if (!send_until_timeout(mp)) {
  349. dispatch_source_cancel(dsp); // stop sending
  350. dispatch_release(dsp);
  351. }
  352. });
  353. dispatch_source_set_cancel_handler(dsp, ^{
  354. test_long("DISPATCH_MACH_SEND_POSSIBLE canceled",
  355. dispatch_source_get_handle(dsp), mp);
  356. test_mach_debug_port(mp);
  357. dispatch_source_cancel(ds); // stop receving
  358. dispatch_release(ds);
  359. });
  360. dispatch_resume(dsp);
  361. dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
  362. test_long("DISPATCH_SOURCE_TYPE_MACH_SEND", sent, TEST_SP_MSGCOUNT);
  363. test_long("DISPATCH_SOURCE_TYPE_MACH_RECV", received, TEST_SP_MSGCOUNT);
  364. }
  365. #else
  366. #define test_send_possible()
  367. #endif
  368. static boolean_t
  369. test_mig_callback(mach_msg_header_t *message __attribute__((unused)),
  370. mach_msg_header_t *reply)
  371. {
  372. __sync_add_and_fetch(&received, 1);
  373. reply->msgh_remote_port = 0;
  374. return false;
  375. }
  376. void
  377. test_mig_server_large_msg(void) // rdar://problem/8422992
  378. {
  379. dispatch_source_t ds;
  380. kern_return_t kr;
  381. mach_port_t mp;
  382. received = 0;
  383. dispatch_group_enter(g);
  384. kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
  385. test_mach_error("mach_port_allocate", kr, KERN_SUCCESS);
  386. kr = mach_port_insert_right(mach_task_self(), mp, mp,
  387. MACH_MSG_TYPE_MAKE_SEND);
  388. test_mach_error("mach_port_insert_right", kr, KERN_SUCCESS);
  389. ds = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0,
  390. dispatch_get_global_queue(0, 0));
  391. dispatch_source_set_event_handler(ds, ^{
  392. mach_msg_return_t r = dispatch_mig_server(ds, sizeof(mach_msg_header_t),
  393. test_mig_callback);
  394. test_mach_error("dispatch_mig_server", r, MACH_RCV_TOO_LARGE);
  395. dispatch_group_leave(g);
  396. });
  397. dispatch_source_set_cancel_handler(ds, ^{
  398. kern_return_t kr = mach_port_mod_refs(mach_task_self(), mp,
  399. MACH_PORT_RIGHT_RECEIVE, -1);
  400. test_mach_error("mach_port_mod_refs", kr, KERN_SUCCESS);
  401. kr = mach_port_deallocate(mach_task_self(), mp);
  402. test_mach_error("mach_port_deallocate", kr, KERN_SUCCESS);
  403. dispatch_group_leave(g);
  404. });
  405. dispatch_resume(ds);
  406. struct { mach_msg_header_t header; char payload[4096]; } msg = {
  407. .header = {
  408. .msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND),
  409. .msgh_size = sizeof(mach_msg_header_t) + 4096,
  410. .msgh_remote_port = mp,
  411. .msgh_id = 0xfeedface,
  412. }
  413. };
  414. kr = mach_msg_send(&msg.header);
  415. test_mach_error("mach_msg_send", kr, KERN_SUCCESS);
  416. dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
  417. dispatch_group_enter(g);
  418. dispatch_source_cancel(ds);
  419. dispatch_release(ds);
  420. test_long("DISPATCH_SOURCE_TYPE_MACH_RECV", received, 0);
  421. dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
  422. }
  423. int
  424. main(void)
  425. {
  426. dispatch_test_start("Dispatch dead-name and send-possible notifications");
  427. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  428. g = dispatch_group_create();
  429. test_dead_name();
  430. test_register_already_dead_name();
  431. test_receive_and_dead_name();
  432. test_send_possible();
  433. test_mig_server_large_msg();
  434. test_stop();
  435. });
  436. dispatch_main();
  437. return 0;
  438. }