bthread_id_unittest.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. // Licensed to the Apache Software Foundation (ASF) under one
  2. // or more contributor license agreements. See the NOTICE file
  3. // distributed with this work for additional information
  4. // regarding copyright ownership. The ASF licenses this file
  5. // to you under the Apache License, Version 2.0 (the
  6. // "License"); you may not use this file except in compliance
  7. // with the License. You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing,
  12. // software distributed under the License is distributed on an
  13. // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. // KIND, either express or implied. See the License for the
  15. // specific language governing permissions and limitations
  16. // under the License.
  17. #include <iostream>
  18. #include <gtest/gtest.h>
  19. #include "butil/time.h"
  20. #include "butil/macros.h"
  21. #include "bthread/bthread.h"
  22. #include "bthread/task_group.h"
  23. #include "bthread/butex.h"
  24. namespace bthread {
  25. void id_status(bthread_id_t, std::ostream &);
  26. uint32_t id_value(bthread_id_t id);
  27. }
  28. namespace {
  29. inline uint32_t get_version(bthread_id_t id) {
  30. return (uint32_t)(id.value & 0xFFFFFFFFul);
  31. }
  32. struct SignalArg {
  33. bthread_id_t id;
  34. long sleep_us_before_fight;
  35. long sleep_us_before_signal;
  36. };
  37. void* signaller(void* void_arg) {
  38. SignalArg arg = *(SignalArg*)void_arg;
  39. bthread_usleep(arg.sleep_us_before_fight);
  40. void* data = NULL;
  41. int rc = bthread_id_trylock(arg.id, &data);
  42. if (rc == 0) {
  43. EXPECT_EQ(0xdead, *(int*)data);
  44. ++*(int*)data;
  45. //EXPECT_EQ(EBUSY, bthread_id_destroy(arg.id, ECANCELED));
  46. bthread_usleep(arg.sleep_us_before_signal);
  47. EXPECT_EQ(0, bthread_id_unlock_and_destroy(arg.id));
  48. return void_arg;
  49. } else {
  50. EXPECT_TRUE(EBUSY == rc || EINVAL == rc);
  51. return NULL;
  52. }
  53. }
  54. TEST(BthreadIdTest, join_after_destroy) {
  55. bthread_id_t id1;
  56. int x = 0xdead;
  57. ASSERT_EQ(0, bthread_id_create_ranged(&id1, &x, NULL, 2));
  58. bthread_id_t id2 = { id1.value + 1 };
  59. ASSERT_EQ(get_version(id1), bthread::id_value(id1));
  60. ASSERT_EQ(get_version(id1), bthread::id_value(id2));
  61. pthread_t th[8];
  62. SignalArg args[ARRAY_SIZE(th)];
  63. for (size_t i = 0; i < ARRAY_SIZE(th); ++i) {
  64. args[i].sleep_us_before_fight = 0;
  65. args[i].sleep_us_before_signal = 0;
  66. args[i].id = (i == 0 ? id1 : id2);
  67. ASSERT_EQ(0, pthread_create(&th[i], NULL, signaller, &args[i]));
  68. }
  69. void* ret[ARRAY_SIZE(th)];
  70. size_t non_null_ret = 0;
  71. for (size_t i = 0; i < ARRAY_SIZE(th); ++i) {
  72. ASSERT_EQ(0, pthread_join(th[i], &ret[i]));
  73. non_null_ret += (ret[i] != NULL);
  74. }
  75. ASSERT_EQ(1UL, non_null_ret);
  76. ASSERT_EQ(0, bthread_id_join(id1));
  77. ASSERT_EQ(0, bthread_id_join(id2));
  78. ASSERT_EQ(0xdead + 1, x);
  79. ASSERT_EQ(get_version(id1) + 5, bthread::id_value(id1));
  80. ASSERT_EQ(get_version(id1) + 5, bthread::id_value(id2));
  81. }
  82. TEST(BthreadIdTest, join_before_destroy) {
  83. bthread_id_t id1;
  84. int x = 0xdead;
  85. ASSERT_EQ(0, bthread_id_create(&id1, &x, NULL));
  86. ASSERT_EQ(get_version(id1), bthread::id_value(id1));
  87. pthread_t th[8];
  88. SignalArg args[ARRAY_SIZE(th)];
  89. for (size_t i = 0; i < ARRAY_SIZE(th); ++i) {
  90. args[i].sleep_us_before_fight = 10000;
  91. args[i].sleep_us_before_signal = 0;
  92. args[i].id = id1;
  93. ASSERT_EQ(0, pthread_create(&th[i], NULL, signaller, &args[i]));
  94. }
  95. ASSERT_EQ(0, bthread_id_join(id1));
  96. ASSERT_EQ(0xdead + 1, x);
  97. ASSERT_EQ(get_version(id1) + 4, bthread::id_value(id1));
  98. void* ret[ARRAY_SIZE(th)];
  99. size_t non_null_ret = 0;
  100. for (size_t i = 0; i < ARRAY_SIZE(th); ++i) {
  101. ASSERT_EQ(0, pthread_join(th[i], &ret[i]));
  102. non_null_ret += (ret[i] != NULL);
  103. }
  104. ASSERT_EQ(1UL, non_null_ret);
  105. }
  106. struct OnResetArg {
  107. bthread_id_t id;
  108. int error_code;
  109. };
  110. int on_reset(bthread_id_t id, void* data, int error_code) {
  111. OnResetArg* arg = static_cast<OnResetArg*>(data);
  112. arg->id = id;
  113. arg->error_code = error_code;
  114. return bthread_id_unlock_and_destroy(id);
  115. }
  116. TEST(BthreadIdTest, error_is_destroy) {
  117. bthread_id_t id1;
  118. OnResetArg arg = { { 0 }, 0 };
  119. ASSERT_EQ(0, bthread_id_create(&id1, &arg, on_reset));
  120. ASSERT_EQ(get_version(id1), bthread::id_value(id1));
  121. ASSERT_EQ(0, bthread_id_error(id1, EBADF));
  122. ASSERT_EQ(EBADF, arg.error_code);
  123. ASSERT_EQ(id1.value, arg.id.value);
  124. ASSERT_EQ(get_version(id1) + 4, bthread::id_value(id1));
  125. }
  126. TEST(BthreadIdTest, error_is_destroy_ranged) {
  127. bthread_id_t id1;
  128. OnResetArg arg = { { 0 }, 0 };
  129. ASSERT_EQ(0, bthread_id_create_ranged(&id1, &arg, on_reset, 2));
  130. bthread_id_t id2 = { id1.value + 1 };
  131. ASSERT_EQ(get_version(id1), bthread::id_value(id2));
  132. ASSERT_EQ(0, bthread_id_error(id2, EBADF));
  133. ASSERT_EQ(EBADF, arg.error_code);
  134. ASSERT_EQ(id2.value, arg.id.value);
  135. ASSERT_EQ(get_version(id1) + 5, bthread::id_value(id2));
  136. }
  137. TEST(BthreadIdTest, default_error_is_destroy) {
  138. bthread_id_t id1;
  139. ASSERT_EQ(0, bthread_id_create(&id1, NULL, NULL));
  140. ASSERT_EQ(get_version(id1), bthread::id_value(id1));
  141. ASSERT_EQ(0, bthread_id_error(id1, EBADF));
  142. ASSERT_EQ(get_version(id1) + 4, bthread::id_value(id1));
  143. }
  144. TEST(BthreadIdTest, doubly_destroy) {
  145. bthread_id_t id1;
  146. ASSERT_EQ(0, bthread_id_create_ranged(&id1, NULL, NULL, 2));
  147. bthread_id_t id2 = { id1.value + 1 };
  148. ASSERT_EQ(get_version(id1), bthread::id_value(id1));
  149. ASSERT_EQ(get_version(id1), bthread::id_value(id2));
  150. ASSERT_EQ(0, bthread_id_error(id1, EBADF));
  151. ASSERT_EQ(get_version(id1) + 5, bthread::id_value(id1));
  152. ASSERT_EQ(get_version(id1) + 5, bthread::id_value(id2));
  153. ASSERT_EQ(EINVAL, bthread_id_error(id1, EBADF));
  154. ASSERT_EQ(EINVAL, bthread_id_error(id2, EBADF));
  155. }
  156. static int on_numeric_error(bthread_id_t id, void* data, int error_code) {
  157. std::vector<int>* result = static_cast<std::vector<int>*>(data);
  158. result->push_back(error_code);
  159. EXPECT_EQ(0, bthread_id_unlock(id));
  160. return 0;
  161. }
  162. TEST(BthreadIdTest, many_error) {
  163. bthread_id_t id1;
  164. std::vector<int> result;
  165. ASSERT_EQ(0, bthread_id_create(&id1, &result, on_numeric_error));
  166. ASSERT_EQ(get_version(id1), bthread::id_value(id1));
  167. int err = 0;
  168. const int N = 100;
  169. for (int i = 0; i < N; ++i) {
  170. ASSERT_EQ(0, bthread_id_error(id1, err++));
  171. }
  172. ASSERT_EQ((size_t)N, result.size());
  173. for (int i = 0; i < N; ++i) {
  174. ASSERT_EQ(i, result[i]);
  175. }
  176. ASSERT_EQ(0, bthread_id_trylock(id1, NULL));
  177. ASSERT_EQ(get_version(id1) + 1, bthread::id_value(id1));
  178. for (int i = 0; i < N; ++i) {
  179. ASSERT_EQ(0, bthread_id_error(id1, err++));
  180. }
  181. ASSERT_EQ((size_t)N, result.size());
  182. ASSERT_EQ(0, bthread_id_unlock(id1));
  183. ASSERT_EQ(get_version(id1), bthread::id_value(id1));
  184. ASSERT_EQ((size_t)2*N, result.size());
  185. for (int i = 0; i < 2*N; ++i) {
  186. EXPECT_EQ(i, result[i]);
  187. }
  188. result.clear();
  189. ASSERT_EQ(0, bthread_id_trylock(id1, NULL));
  190. ASSERT_EQ(get_version(id1) + 1, bthread::id_value(id1));
  191. for (int i = 0; i < N; ++i) {
  192. ASSERT_EQ(0, bthread_id_error(id1, err++));
  193. }
  194. ASSERT_EQ(0, bthread_id_unlock_and_destroy(id1));
  195. ASSERT_TRUE(result.empty());
  196. }
  197. static void* locker(void* arg) {
  198. bthread_id_t id = { (uintptr_t)arg };
  199. butil::Timer tm;
  200. tm.start();
  201. EXPECT_EQ(0, bthread_id_lock(id, NULL));
  202. bthread_usleep(2000);
  203. EXPECT_EQ(0, bthread_id_unlock(id));
  204. tm.stop();
  205. LOG(INFO) << "Unlocked, tm=" << tm.u_elapsed();
  206. return NULL;
  207. }
  208. TEST(BthreadIdTest, id_lock) {
  209. bthread_id_t id1;
  210. ASSERT_EQ(0, bthread_id_create(&id1, NULL, NULL));
  211. ASSERT_EQ(get_version(id1), bthread::id_value(id1));
  212. pthread_t th[8];
  213. for (size_t i = 0; i < ARRAY_SIZE(th); ++i) {
  214. ASSERT_EQ(0, pthread_create(&th[i], NULL, locker,
  215. (void*)id1.value));
  216. }
  217. for (size_t i = 0; i < ARRAY_SIZE(th); ++i) {
  218. ASSERT_EQ(0, pthread_join(th[i], NULL));
  219. }
  220. }
  221. static void* failed_locker(void* arg) {
  222. bthread_id_t id = { (uintptr_t)arg };
  223. int rc = bthread_id_lock(id, NULL);
  224. if (rc == 0) {
  225. bthread_usleep(2000);
  226. EXPECT_EQ(0, bthread_id_unlock_and_destroy(id));
  227. return (void*)1;
  228. } else {
  229. EXPECT_EQ(EINVAL, rc);
  230. return NULL;
  231. }
  232. }
  233. TEST(BthreadIdTest, id_lock_and_destroy) {
  234. bthread_id_t id1;
  235. ASSERT_EQ(0, bthread_id_create(&id1, NULL, NULL));
  236. ASSERT_EQ(get_version(id1), bthread::id_value(id1));
  237. pthread_t th[8];
  238. for (size_t i = 0; i < ARRAY_SIZE(th); ++i) {
  239. ASSERT_EQ(0, pthread_create(&th[i], NULL, failed_locker,
  240. (void*)id1.value));
  241. }
  242. int non_null = 0;
  243. for (size_t i = 0; i < ARRAY_SIZE(th); ++i) {
  244. void* ret = NULL;
  245. ASSERT_EQ(0, pthread_join(th[i], &ret));
  246. non_null += (ret != NULL);
  247. }
  248. ASSERT_EQ(1, non_null);
  249. }
  250. TEST(BthreadIdTest, join_after_destroy_before_unlock) {
  251. bthread_id_t id1;
  252. int x = 0xdead;
  253. ASSERT_EQ(0, bthread_id_create(&id1, &x, NULL));
  254. ASSERT_EQ(get_version(id1), bthread::id_value(id1));
  255. pthread_t th[8];
  256. SignalArg args[ARRAY_SIZE(th)];
  257. for (size_t i = 0; i < ARRAY_SIZE(th); ++i) {
  258. args[i].sleep_us_before_fight = 0;
  259. args[i].sleep_us_before_signal = 20000;
  260. args[i].id = id1;
  261. ASSERT_EQ(0, pthread_create(&th[i], NULL, signaller, &args[i]));
  262. }
  263. bthread_usleep(10000);
  264. // join() waits until destroy() is called.
  265. ASSERT_EQ(0, bthread_id_join(id1));
  266. ASSERT_EQ(0xdead + 1, x);
  267. ASSERT_EQ(get_version(id1) + 4, bthread::id_value(id1));
  268. void* ret[ARRAY_SIZE(th)];
  269. size_t non_null_ret = 0;
  270. for (size_t i = 0; i < ARRAY_SIZE(th); ++i) {
  271. ASSERT_EQ(0, pthread_join(th[i], &ret[i]));
  272. non_null_ret += (ret[i] != NULL);
  273. }
  274. ASSERT_EQ(1UL, non_null_ret);
  275. }
  276. struct StoppedWaiterArgs {
  277. bthread_id_t id;
  278. bool thread_started;
  279. };
  280. void* stopped_waiter(void* void_arg) {
  281. StoppedWaiterArgs* args = (StoppedWaiterArgs*)void_arg;
  282. args->thread_started = true;
  283. EXPECT_EQ(0, bthread_id_join(args->id));
  284. EXPECT_EQ(get_version(args->id) + 4, bthread::id_value(args->id));
  285. return NULL;
  286. }
  287. TEST(BthreadIdTest, stop_a_wait_after_fight_before_signal) {
  288. bthread_id_t id1;
  289. int x = 0xdead;
  290. ASSERT_EQ(0, bthread_id_create(&id1, &x, NULL));
  291. ASSERT_EQ(get_version(id1), bthread::id_value(id1));
  292. void* data;
  293. ASSERT_EQ(0, bthread_id_trylock(id1, &data));
  294. ASSERT_EQ(&x, data);
  295. bthread_t th[8];
  296. StoppedWaiterArgs args[ARRAY_SIZE(th)];
  297. for (size_t i = 0; i < ARRAY_SIZE(th); ++i) {
  298. args[i].id = id1;
  299. args[i].thread_started = false;
  300. ASSERT_EQ(0, bthread_start_urgent(&th[i], NULL, stopped_waiter, &args[i]));
  301. }
  302. // stop does not wake up bthread_id_join
  303. for (size_t i = 0; i < ARRAY_SIZE(th); ++i) {
  304. bthread_stop(th[i]);
  305. }
  306. bthread_usleep(10000);
  307. for (size_t i = 0; i < ARRAY_SIZE(th); ++i) {
  308. ASSERT_TRUE(bthread::TaskGroup::exists(th[i]));
  309. }
  310. // destroy the id to end the joinings.
  311. ASSERT_EQ(0, bthread_id_unlock_and_destroy(id1));
  312. for (size_t i = 0; i < ARRAY_SIZE(th); ++i) {
  313. ASSERT_EQ(0, bthread_join(th[i], NULL));
  314. }
  315. }
  316. void* waiter(void* arg) {
  317. bthread_id_t id = { (uintptr_t)arg };
  318. EXPECT_EQ(0, bthread_id_join(id));
  319. EXPECT_EQ(get_version(id) + 4, bthread::id_value(id));
  320. return NULL;
  321. }
  322. int handle_data(bthread_id_t id, void* data, int error_code) {
  323. EXPECT_EQ(EBADF, error_code);
  324. ++*(int*)data;
  325. EXPECT_EQ(0, bthread_id_unlock_and_destroy(id));
  326. return 0;
  327. }
  328. TEST(BthreadIdTest, list_signal) {
  329. bthread_id_list_t list;
  330. ASSERT_EQ(0, bthread_id_list_init(&list, 32, 32));
  331. bthread_id_t id[16];
  332. int data[ARRAY_SIZE(id)];
  333. for (size_t i = 0; i < ARRAY_SIZE(id); ++i) {
  334. data[i] = i;
  335. ASSERT_EQ(0, bthread_id_create(&id[i], &data[i], handle_data));
  336. ASSERT_EQ(get_version(id[i]), bthread::id_value(id[i]));
  337. ASSERT_EQ(0, bthread_id_list_add(&list, id[i]));
  338. }
  339. pthread_t th[ARRAY_SIZE(id)];
  340. for (size_t i = 0; i < ARRAY_SIZE(th); ++i) {
  341. ASSERT_EQ(0, pthread_create(&th[i], NULL, waiter, (void*)(intptr_t)id[i].value));
  342. }
  343. bthread_usleep(10000);
  344. ASSERT_EQ(0, bthread_id_list_reset(&list, EBADF));
  345. for (size_t i = 0; i < ARRAY_SIZE(th); ++i) {
  346. ASSERT_EQ((int)(i + 1), data[i]);
  347. ASSERT_EQ(0, pthread_join(th[i], NULL));
  348. // already reset.
  349. ASSERT_EQ((int)(i + 1), data[i]);
  350. }
  351. bthread_id_list_destroy(&list);
  352. }
  353. int error_without_unlock(bthread_id_t, void *, int) {
  354. return 0;
  355. }
  356. TEST(BthreadIdTest, status) {
  357. bthread_id_t id;
  358. bthread_id_create(&id, NULL, NULL);
  359. bthread::id_status(id, std::cout);
  360. bthread_id_lock(id, NULL);
  361. bthread_id_error(id, 123);
  362. bthread_id_error(id, 256);
  363. bthread_id_error(id, 1256);
  364. bthread::id_status(id, std::cout);
  365. bthread_id_unlock_and_destroy(id);
  366. bthread_id_create(&id, NULL, error_without_unlock);
  367. bthread_id_lock(id, NULL);
  368. bthread::id_status(id, std::cout);
  369. bthread_id_error(id, 12);
  370. bthread::id_status(id, std::cout);
  371. bthread_id_unlock(id);
  372. bthread::id_status(id, std::cout);
  373. bthread_id_unlock_and_destroy(id);
  374. }
  375. TEST(BthreadIdTest, reset_range) {
  376. bthread_id_t id;
  377. ASSERT_EQ(0, bthread_id_create(&id, NULL, NULL));
  378. ASSERT_EQ(0, bthread_id_lock_and_reset_range(id, NULL, 1000));
  379. bthread::id_status(id, std::cout);
  380. bthread_id_unlock(id);
  381. ASSERT_EQ(0, bthread_id_lock_and_reset_range(id, NULL, 300));
  382. bthread::id_status(id, std::cout);
  383. bthread_id_unlock_and_destroy(id);
  384. }
  385. static bool any_thread_quit = false;
  386. struct FailToLockIdArgs {
  387. bthread_id_t id;
  388. int expected_return;
  389. };
  390. static void* fail_to_lock_id(void* args_in) {
  391. FailToLockIdArgs* args = (FailToLockIdArgs*)args_in;
  392. butil::Timer tm;
  393. EXPECT_EQ(args->expected_return, bthread_id_lock(args->id, NULL));
  394. any_thread_quit = true;
  395. return NULL;
  396. }
  397. TEST(BthreadIdTest, about_to_destroy_before_locking) {
  398. bthread_id_t id;
  399. ASSERT_EQ(0, bthread_id_create(&id, NULL, NULL));
  400. ASSERT_EQ(0, bthread_id_lock(id, NULL));
  401. ASSERT_EQ(0, bthread_id_about_to_destroy(id));
  402. pthread_t pth;
  403. bthread_t bth;
  404. FailToLockIdArgs args = { id, EPERM };
  405. ASSERT_EQ(0, pthread_create(&pth, NULL, fail_to_lock_id, &args));
  406. ASSERT_EQ(0, bthread_start_background(&bth, NULL, fail_to_lock_id, &args));
  407. // The threads should quit soon.
  408. pthread_join(pth, NULL);
  409. bthread_join(bth, NULL);
  410. bthread::id_status(id, std::cout);
  411. ASSERT_EQ(0, bthread_id_unlock_and_destroy(id));
  412. }
  413. static void* succeed_to_lock_id(void* arg) {
  414. bthread_id_t id = *(bthread_id_t*)arg;
  415. EXPECT_EQ(0, bthread_id_lock(id, NULL));
  416. EXPECT_EQ(0, bthread_id_unlock(id));
  417. return NULL;
  418. }
  419. TEST(BthreadIdTest, about_to_destroy_cancelled) {
  420. bthread_id_t id;
  421. ASSERT_EQ(0, bthread_id_create(&id, NULL, NULL));
  422. ASSERT_EQ(0, bthread_id_lock(id, NULL));
  423. ASSERT_EQ(0, bthread_id_about_to_destroy(id));
  424. ASSERT_EQ(0, bthread_id_unlock(id));
  425. pthread_t pth;
  426. bthread_t bth;
  427. ASSERT_EQ(0, pthread_create(&pth, NULL, succeed_to_lock_id, &id));
  428. ASSERT_EQ(0, bthread_start_background(&bth, NULL, succeed_to_lock_id, &id));
  429. // The threads should quit soon.
  430. pthread_join(pth, NULL);
  431. bthread_join(bth, NULL);
  432. bthread::id_status(id, std::cout);
  433. ASSERT_EQ(0, bthread_id_lock(id, NULL));
  434. ASSERT_EQ(0, bthread_id_unlock_and_destroy(id));
  435. }
  436. TEST(BthreadIdTest, about_to_destroy_during_locking) {
  437. bthread_id_t id;
  438. ASSERT_EQ(0, bthread_id_create(&id, NULL, NULL));
  439. ASSERT_EQ(0, bthread_id_lock(id, NULL));
  440. any_thread_quit = false;
  441. pthread_t pth;
  442. bthread_t bth;
  443. FailToLockIdArgs args = { id, EPERM };
  444. ASSERT_EQ(0, pthread_create(&pth, NULL, fail_to_lock_id, &args));
  445. ASSERT_EQ(0, bthread_start_background(&bth, NULL, fail_to_lock_id, &args));
  446. usleep(100000);
  447. ASSERT_FALSE(any_thread_quit);
  448. ASSERT_EQ(0, bthread_id_about_to_destroy(id));
  449. // The threads should quit soon.
  450. pthread_join(pth, NULL);
  451. bthread_join(bth, NULL);
  452. bthread::id_status(id, std::cout);
  453. ASSERT_EQ(0, bthread_id_unlock_and_destroy(id));
  454. }
  455. void* const DUMMY_DATA1 = (void*)1;
  456. void* const DUMMY_DATA2 = (void*)2;
  457. int branch_counter = 0;
  458. int branch_tags[4] = {};
  459. int expected_code = 0;
  460. const char* expected_desc = "";
  461. int handler_without_desc(bthread_id_t id, void* data, int error_code) {
  462. EXPECT_EQ(DUMMY_DATA1, data);
  463. EXPECT_EQ(expected_code, error_code);
  464. if (error_code == ESTOP) {
  465. branch_tags[0] = branch_counter;
  466. return bthread_id_unlock_and_destroy(id);
  467. } else {
  468. branch_tags[1] = branch_counter;
  469. return bthread_id_unlock(id);
  470. }
  471. }
  472. int handler_with_desc(bthread_id_t id, void* data, int error_code,
  473. const std::string& error_text) {
  474. EXPECT_EQ(DUMMY_DATA2, data);
  475. EXPECT_EQ(expected_code, error_code);
  476. EXPECT_STREQ(expected_desc, error_text.c_str());
  477. if (error_code == ESTOP) {
  478. branch_tags[2] = branch_counter;
  479. return bthread_id_unlock_and_destroy(id);
  480. } else {
  481. branch_tags[3] = branch_counter;
  482. return bthread_id_unlock(id);
  483. }
  484. }
  485. TEST(BthreadIdTest, error_with_descriptions) {
  486. bthread_id_t id1;
  487. ASSERT_EQ(0, bthread_id_create(&id1, DUMMY_DATA1, handler_without_desc));
  488. bthread_id_t id2;
  489. ASSERT_EQ(0, bthread_id_create2(&id2, DUMMY_DATA2, handler_with_desc));
  490. // [ Matched in-place ]
  491. // Call bthread_id_error on an id created by bthread_id_create
  492. ++branch_counter;
  493. expected_code = EINVAL;
  494. ASSERT_EQ(0, bthread_id_error(id1, expected_code));
  495. ASSERT_EQ(branch_counter, branch_tags[1]);
  496. // Call bthread_id_error2 on an id created by bthread_id_create2
  497. ++branch_counter;
  498. expected_code = EPERM;
  499. expected_desc = "description1";
  500. ASSERT_EQ(0, bthread_id_error2(id2, expected_code, expected_desc));
  501. ASSERT_EQ(branch_counter, branch_tags[3]);
  502. // [ Mixed in-place ]
  503. // Call bthread_id_error on an id created by bthread_id_create2
  504. ++branch_counter;
  505. expected_code = ECONNREFUSED;
  506. expected_desc = "";
  507. ASSERT_EQ(0, bthread_id_error(id2, expected_code));
  508. ASSERT_EQ(branch_counter, branch_tags[3]);
  509. // Call bthread_id_error2 on an id created by bthread_id_create
  510. ++branch_counter;
  511. expected_code = EINTR;
  512. ASSERT_EQ(0, bthread_id_error2(id1, expected_code, ""));
  513. ASSERT_EQ(branch_counter, branch_tags[1]);
  514. // [ Matched pending ]
  515. // Call bthread_id_error on an id created by bthread_id_create
  516. ++branch_counter;
  517. expected_code = ECONNRESET;
  518. ASSERT_EQ(0, bthread_id_lock(id1, NULL));
  519. ASSERT_EQ(0, bthread_id_error(id1, expected_code));
  520. ASSERT_EQ(0, bthread_id_unlock(id1));
  521. ASSERT_EQ(branch_counter, branch_tags[1]);
  522. // Call bthread_id_error2 on an id created by bthread_id_create2
  523. ++branch_counter;
  524. expected_code = ENOSPC;
  525. expected_desc = "description3";
  526. ASSERT_EQ(0, bthread_id_lock(id2, NULL));
  527. ASSERT_EQ(0, bthread_id_error2(id2, expected_code, expected_desc));
  528. ASSERT_EQ(0, bthread_id_unlock(id2));
  529. ASSERT_EQ(branch_counter, branch_tags[3]);
  530. // [ Mixed pending ]
  531. // Call bthread_id_error on an id created by bthread_id_create2
  532. ++branch_counter;
  533. expected_code = ESTOP;
  534. expected_desc = "";
  535. ASSERT_EQ(0, bthread_id_lock(id2, NULL));
  536. ASSERT_EQ(0, bthread_id_error(id2, expected_code));
  537. ASSERT_EQ(0, bthread_id_unlock(id2));
  538. ASSERT_EQ(branch_counter, branch_tags[2]);
  539. // Call bthread_id_error2 on an id created by bthread_id_create
  540. ++branch_counter;
  541. ASSERT_EQ(0, bthread_id_lock(id1, NULL));
  542. ASSERT_EQ(0, bthread_id_error2(id1, expected_code, ""));
  543. ASSERT_EQ(0, bthread_id_unlock(id1));
  544. ASSERT_EQ(branch_counter, branch_tags[0]);
  545. }
  546. } // namespace