rfork.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. #include <u.h>
  2. #include <sys/wait.h>
  3. #include <signal.h>
  4. #include <libc.h>
  5. #undef rfork
  6. static void
  7. nop(int x)
  8. {
  9. USED(x);
  10. }
  11. int
  12. p9rfork(int flags)
  13. {
  14. int pid, status;
  15. int p[2];
  16. int n;
  17. char buf[128], *q;
  18. extern char **environ;
  19. if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
  20. /* check other flags before we commit */
  21. flags &= ~(RFPROC|RFFDG|RFENVG);
  22. n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT|RFCENVG));
  23. if(n){
  24. werrstr("unknown flags %08ux in rfork", n);
  25. return -1;
  26. }
  27. if(flags&RFNOWAIT){
  28. /*
  29. * BUG - should put the signal handler back after we
  30. * finish, but I just don't care. If a program calls with
  31. * NOWAIT once, they're not likely to want child notes
  32. * after that.
  33. */
  34. signal(SIGCHLD, nop);
  35. if(pipe(p) < 0)
  36. return -1;
  37. }
  38. pid = fork();
  39. if(pid == -1)
  40. return -1;
  41. if(flags&RFNOWAIT){
  42. flags &= ~RFNOWAIT;
  43. if(pid){
  44. /*
  45. * Parent - wait for child to fork wait-free child.
  46. * Then read pid from pipe. Assume pipe buffer can absorb the write.
  47. */
  48. close(p[1]);
  49. status = 0;
  50. if(wait4(pid, &status, 0, 0) < 0){
  51. werrstr("pipe dance - wait4 - %r");
  52. close(p[0]);
  53. return -1;
  54. }
  55. n = readn(p[0], buf, sizeof buf-1);
  56. close(p[0]);
  57. if(!WIFEXITED(status) || WEXITSTATUS(status)!=0 || n <= 0){
  58. if(!WIFEXITED(status))
  59. werrstr("pipe dance - !exited 0x%ux", status);
  60. else if(WEXITSTATUS(status) != 0)
  61. werrstr("pipe dance - non-zero status 0x%ux", status);
  62. else if(n < 0)
  63. werrstr("pipe dance - pipe read error - %r");
  64. else if(n == 0)
  65. werrstr("pipe dance - pipe read eof");
  66. else
  67. werrstr("pipe dance - unknown failure");
  68. return -1;
  69. }
  70. buf[n] = 0;
  71. if(buf[0] == 'x'){
  72. werrstr("%s", buf+2);
  73. return -1;
  74. }
  75. pid = strtol(buf, &q, 0);
  76. }else{
  77. /*
  78. * Child - fork a new child whose wait message can't
  79. * get back to the parent because we're going to exit!
  80. */
  81. signal(SIGCHLD, SIG_IGN);
  82. close(p[0]);
  83. pid = fork();
  84. if(pid){
  85. /* Child parent - send status over pipe and exit. */
  86. if(pid > 0)
  87. fprint(p[1], "%d", pid);
  88. else
  89. fprint(p[1], "x %r");
  90. close(p[1]);
  91. _exit(0);
  92. }else{
  93. /* Child child - close pipe. */
  94. close(p[1]);
  95. }
  96. }
  97. }
  98. if(pid != 0)
  99. return pid;
  100. if(flags&RFCENVG)
  101. if(environ)
  102. *environ = nil;
  103. }
  104. if(flags&RFPROC){
  105. werrstr("cannot use rfork for shared memory -- use libthread");
  106. return -1;
  107. }
  108. if(flags&RFNAMEG){
  109. /* XXX set $NAMESPACE to a new directory */
  110. flags &= ~RFNAMEG;
  111. }
  112. if(flags&RFNOTEG){
  113. setpgid(0, getpid());
  114. flags &= ~RFNOTEG;
  115. }
  116. if(flags&RFNOWAIT){
  117. werrstr("cannot use RFNOWAIT without RFPROC");
  118. return -1;
  119. }
  120. if(flags){
  121. werrstr("unknown flags %08ux in rfork", flags);
  122. return -1;
  123. }
  124. return 0;
  125. }