api-fork-test.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /* Test forking while holding lock.
  2. *
  3. * There are only five ways to do this currently:
  4. * (1) grab a ntdb_chainlock, then fork.
  5. * (2) grab a ntdb_lockall, then fork.
  6. * (3) grab a ntdb_lockall_read, then fork.
  7. * (4) start a transaction, then fork.
  8. * (5) fork from inside a ntdb_parse() callback.
  9. *
  10. * Note that we don't hold a lock across ntdb_traverse callbacks, so
  11. * that doesn't matter.
  12. */
  13. #include "config.h"
  14. #include "../ntdb.h"
  15. #include "../private.h"
  16. #include "tap-interface.h"
  17. #include "logging.h"
  18. #include "helpapi-external-agent.h"
  19. static bool am_child = false;
  20. static enum NTDB_ERROR fork_in_parse(NTDB_DATA key, NTDB_DATA data,
  21. struct ntdb_context *ntdb)
  22. {
  23. int status;
  24. if (fork() == 0) {
  25. am_child = true;
  26. /* We expect this to fail. */
  27. if (ntdb_store(ntdb, key, data, NTDB_REPLACE) != NTDB_ERR_LOCK)
  28. exit(1);
  29. if (ntdb_fetch(ntdb, key, &data) != NTDB_ERR_LOCK)
  30. exit(1);
  31. if (tap_log_messages != 2)
  32. exit(2);
  33. return NTDB_SUCCESS;
  34. }
  35. wait(&status);
  36. ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
  37. return NTDB_SUCCESS;
  38. }
  39. int main(int argc, char *argv[])
  40. {
  41. unsigned int i;
  42. struct ntdb_context *ntdb;
  43. int flags[] = { NTDB_DEFAULT, NTDB_NOMMAP,
  44. NTDB_CONVERT, NTDB_NOMMAP|NTDB_CONVERT };
  45. NTDB_DATA key = ntdb_mkdata("key", 3);
  46. NTDB_DATA data = ntdb_mkdata("data", 4);
  47. plan_tests(sizeof(flags) / sizeof(flags[0]) * 14);
  48. for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
  49. int status;
  50. tap_log_messages = 0;
  51. ntdb = ntdb_open("run-fork-test.ntdb",
  52. flags[i]|MAYBE_NOSYNC,
  53. O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
  54. if (!ok1(ntdb))
  55. continue;
  56. /* Put a record in here. */
  57. ok1(ntdb_store(ntdb, key, data, NTDB_REPLACE) == NTDB_SUCCESS);
  58. ok1(ntdb_chainlock(ntdb, key) == NTDB_SUCCESS);
  59. if (fork() == 0) {
  60. /* We expect this to fail. */
  61. if (ntdb_store(ntdb, key, data, NTDB_REPLACE) != NTDB_ERR_LOCK)
  62. return 1;
  63. if (ntdb_fetch(ntdb, key, &data) != NTDB_ERR_LOCK)
  64. return 1;
  65. if (tap_log_messages != 2)
  66. return 2;
  67. /* Child can do this without any complaints. */
  68. ntdb_chainunlock(ntdb, key);
  69. if (tap_log_messages != 2)
  70. return 3;
  71. ntdb_close(ntdb);
  72. if (tap_log_messages != 2)
  73. return 4;
  74. return 0;
  75. }
  76. wait(&status);
  77. ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
  78. ntdb_chainunlock(ntdb, key);
  79. ok1(ntdb_lockall(ntdb) == NTDB_SUCCESS);
  80. if (fork() == 0) {
  81. /* We expect this to fail. */
  82. if (ntdb_store(ntdb, key, data, NTDB_REPLACE) != NTDB_ERR_LOCK)
  83. return 1;
  84. if (ntdb_fetch(ntdb, key, &data) != NTDB_ERR_LOCK)
  85. return 1;
  86. if (tap_log_messages != 2)
  87. return 2;
  88. /* Child can do this without any complaints. */
  89. ntdb_unlockall(ntdb);
  90. if (tap_log_messages != 2)
  91. return 3;
  92. ntdb_close(ntdb);
  93. if (tap_log_messages != 2)
  94. return 4;
  95. return 0;
  96. }
  97. wait(&status);
  98. ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
  99. ntdb_unlockall(ntdb);
  100. ok1(ntdb_lockall_read(ntdb) == NTDB_SUCCESS);
  101. if (fork() == 0) {
  102. /* We expect this to fail. */
  103. /* This would always fail anyway... */
  104. if (ntdb_store(ntdb, key, data, NTDB_REPLACE) != NTDB_ERR_LOCK)
  105. return 1;
  106. if (ntdb_fetch(ntdb, key, &data) != NTDB_ERR_LOCK)
  107. return 1;
  108. if (tap_log_messages != 2)
  109. return 2;
  110. /* Child can do this without any complaints. */
  111. ntdb_unlockall_read(ntdb);
  112. if (tap_log_messages != 2)
  113. return 3;
  114. ntdb_close(ntdb);
  115. if (tap_log_messages != 2)
  116. return 4;
  117. return 0;
  118. }
  119. wait(&status);
  120. ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
  121. ntdb_unlockall_read(ntdb);
  122. ok1(ntdb_transaction_start(ntdb) == NTDB_SUCCESS);
  123. /* If transactions is empty, noop "commit" succeeds. */
  124. ok1(ntdb_delete(ntdb, key) == NTDB_SUCCESS);
  125. if (fork() == 0) {
  126. int last_log_messages;
  127. /* We expect this to fail. */
  128. if (ntdb_store(ntdb, key, data, NTDB_REPLACE) != NTDB_ERR_LOCK)
  129. return 1;
  130. if (ntdb_fetch(ntdb, key, &data) != NTDB_ERR_LOCK)
  131. return 1;
  132. if (tap_log_messages != 2)
  133. return 2;
  134. if (ntdb_transaction_prepare_commit(ntdb)
  135. != NTDB_ERR_LOCK)
  136. return 3;
  137. if (tap_log_messages == 2)
  138. return 4;
  139. last_log_messages = tap_log_messages;
  140. /* Child can do this without any complaints. */
  141. ntdb_transaction_cancel(ntdb);
  142. if (tap_log_messages != last_log_messages)
  143. return 4;
  144. ntdb_close(ntdb);
  145. if (tap_log_messages != last_log_messages)
  146. return 4;
  147. return 0;
  148. }
  149. wait(&status);
  150. ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
  151. ntdb_transaction_cancel(ntdb);
  152. ok1(ntdb_parse_record(ntdb, key, fork_in_parse, ntdb)
  153. == NTDB_SUCCESS);
  154. ntdb_close(ntdb);
  155. if (am_child) {
  156. /* Child can return from parse without complaints. */
  157. if (tap_log_messages != 2)
  158. exit(3);
  159. exit(0);
  160. }
  161. ok1(tap_log_messages == 0);
  162. }
  163. return exit_status();
  164. }