comparison nspr/pr/src/md/unix/uxproces.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e5118fa0cb1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "primpl.h"
7
8 #include <sys/types.h>
9 #include <unistd.h>
10 #include <fcntl.h>
11 #include <signal.h>
12 #include <sys/wait.h>
13 #include <string.h>
14 #if defined(AIX)
15 #include <dlfcn.h> /* For dlopen, dlsym, dlclose */
16 #endif
17
18 #if defined(DARWIN)
19 #if defined(HAVE_CRT_EXTERNS_H)
20 #include <crt_externs.h>
21 #endif
22 #else
23 PR_IMPORT_DATA(char **) environ;
24 #endif
25
26 /*
27 * HP-UX 9 doesn't have the SA_RESTART flag.
28 */
29 #ifndef SA_RESTART
30 #define SA_RESTART 0
31 #endif
32
33 /*
34 **********************************************************************
35 *
36 * The Unix process routines
37 *
38 **********************************************************************
39 */
40
41 #define _PR_SIGNALED_EXITSTATUS 256
42
43 typedef enum pr_PidState {
44 _PR_PID_DETACHED,
45 _PR_PID_REAPED,
46 _PR_PID_WAITING
47 } pr_PidState;
48
49 typedef struct pr_PidRecord {
50 pid_t pid;
51 int exitStatus;
52 pr_PidState state;
53 PRCondVar *reapedCV;
54 struct pr_PidRecord *next;
55 } pr_PidRecord;
56
57 /*
58 * Irix sprocs and LinuxThreads are actually a kind of processes
59 * that can share the virtual address space and file descriptors.
60 */
61 #if (defined(IRIX) && !defined(_PR_PTHREADS)) \
62 || ((defined(LINUX) || defined(__GNU__) || defined(__GLIBC__)) \
63 && defined(_PR_PTHREADS))
64 #define _PR_SHARE_CLONES
65 #endif
66
67 /*
68 * The macro _PR_NATIVE_THREADS indicates that we are
69 * using native threads only, so waitpid() blocks just the
70 * calling thread, not the process. In this case, the waitpid
71 * daemon thread can safely block in waitpid(). So we don't
72 * need to catch SIGCHLD, and the pipe to unblock PR_Poll() is
73 * also not necessary.
74 */
75
76 #if defined(_PR_GLOBAL_THREADS_ONLY) \
77 || (defined(_PR_PTHREADS) \
78 && !defined(LINUX) && !defined(__GNU__) && !defined(__GLIBC__))
79 #define _PR_NATIVE_THREADS
80 #endif
81
82 /*
83 * All the static variables used by the Unix process routines are
84 * collected in this structure.
85 */
86
87 static struct {
88 PRCallOnceType once;
89 PRThread *thread;
90 PRLock *ml;
91 #if defined(_PR_NATIVE_THREADS)
92 PRInt32 numProcs;
93 PRCondVar *cv;
94 #else
95 int pipefd[2];
96 #endif
97 pr_PidRecord **pidTable;
98
99 #ifdef _PR_SHARE_CLONES
100 struct pr_CreateProcOp *opHead, *opTail;
101 #endif
102
103 #ifdef AIX
104 pid_t (*forkptr)(void); /* Newer versions of AIX (starting in 4.3.2)
105 * have f_fork, which is faster than the
106 * regular fork in a multithreaded process
107 * because it skips calling the fork handlers.
108 * So we look up the f_fork symbol to see if
109 * it's available and fall back on fork.
110 */
111 #endif /* AIX */
112 } pr_wp;
113
114 #ifdef _PR_SHARE_CLONES
115 static int pr_waitpid_daemon_exit;
116
117 void
118 _MD_unix_terminate_waitpid_daemon(void)
119 {
120 if (pr_wp.thread) {
121 pr_waitpid_daemon_exit = 1;
122 write(pr_wp.pipefd[1], "", 1);
123 PR_JoinThread(pr_wp.thread);
124 }
125 }
126 #endif
127
128 static PRStatus _MD_InitProcesses(void);
129 #if !defined(_PR_NATIVE_THREADS)
130 static void pr_InstallSigchldHandler(void);
131 #endif
132
133 static PRProcess *
134 ForkAndExec(
135 const char *path,
136 char *const *argv,
137 char *const *envp,
138 const PRProcessAttr *attr)
139 {
140 PRProcess *process;
141 int nEnv, idx;
142 char *const *childEnvp;
143 char **newEnvp = NULL;
144 int flags;
145
146 process = PR_NEW(PRProcess);
147 if (!process) {
148 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
149 return NULL;
150 }
151
152 childEnvp = envp;
153 if (attr && attr->fdInheritBuffer) {
154 PRBool found = PR_FALSE;
155
156 if (NULL == childEnvp) {
157 #ifdef DARWIN
158 #ifdef HAVE_CRT_EXTERNS_H
159 childEnvp = *(_NSGetEnviron());
160 #else
161 /* _NSGetEnviron() is not available on iOS. */
162 PR_DELETE(process);
163 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
164 return NULL;
165 #endif
166 #else
167 childEnvp = environ;
168 #endif
169 }
170
171 for (nEnv = 0; childEnvp[nEnv]; nEnv++) {
172 }
173 newEnvp = (char **) PR_MALLOC((nEnv + 2) * sizeof(char *));
174 if (NULL == newEnvp) {
175 PR_DELETE(process);
176 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
177 return NULL;
178 }
179 for (idx = 0; idx < nEnv; idx++) {
180 newEnvp[idx] = childEnvp[idx];
181 if (!found && !strncmp(newEnvp[idx], "NSPR_INHERIT_FDS=", 17)) {
182 newEnvp[idx] = attr->fdInheritBuffer;
183 found = PR_TRUE;
184 }
185 }
186 if (!found) {
187 newEnvp[idx++] = attr->fdInheritBuffer;
188 }
189 newEnvp[idx] = NULL;
190 childEnvp = newEnvp;
191 }
192
193 #ifdef AIX
194 process->md.pid = (*pr_wp.forkptr)();
195 #elif defined(NTO) || defined(SYMBIAN)
196 /*
197 * fork() & exec() does not work in a multithreaded process.
198 * Use spawn() instead.
199 */
200 {
201 int fd_map[3] = { 0, 1, 2 };
202
203 if (attr) {
204 if (attr->stdinFd && attr->stdinFd->secret->md.osfd != 0) {
205 fd_map[0] = dup(attr->stdinFd->secret->md.osfd);
206 flags = fcntl(fd_map[0], F_GETFL, 0);
207 if (flags & O_NONBLOCK)
208 fcntl(fd_map[0], F_SETFL, flags & ~O_NONBLOCK);
209 }
210 if (attr->stdoutFd && attr->stdoutFd->secret->md.osfd != 1) {
211 fd_map[1] = dup(attr->stdoutFd->secret->md.osfd);
212 flags = fcntl(fd_map[1], F_GETFL, 0);
213 if (flags & O_NONBLOCK)
214 fcntl(fd_map[1], F_SETFL, flags & ~O_NONBLOCK);
215 }
216 if (attr->stderrFd && attr->stderrFd->secret->md.osfd != 2) {
217 fd_map[2] = dup(attr->stderrFd->secret->md.osfd);
218 flags = fcntl(fd_map[2], F_GETFL, 0);
219 if (flags & O_NONBLOCK)
220 fcntl(fd_map[2], F_SETFL, flags & ~O_NONBLOCK);
221 }
222
223 PR_ASSERT(attr->currentDirectory == NULL); /* not implemented */
224 }
225
226 #ifdef SYMBIAN
227 /* In Symbian OS, we use posix_spawn instead of fork() and exec() */
228 posix_spawn(&(process->md.pid), path, NULL, NULL, argv, childEnvp);
229 #else
230 process->md.pid = spawn(path, 3, fd_map, NULL, argv, childEnvp);
231 #endif
232
233 if (fd_map[0] != 0)
234 close(fd_map[0]);
235 if (fd_map[1] != 1)
236 close(fd_map[1]);
237 if (fd_map[2] != 2)
238 close(fd_map[2]);
239 }
240 #else
241 process->md.pid = fork();
242 #endif
243 if ((pid_t) -1 == process->md.pid) {
244 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, errno);
245 PR_DELETE(process);
246 if (newEnvp) {
247 PR_DELETE(newEnvp);
248 }
249 return NULL;
250 } else if (0 == process->md.pid) { /* the child process */
251 /*
252 * If the child process needs to exit, it must call _exit().
253 * Do not call exit(), because exit() will flush and close
254 * the standard I/O file descriptors, and hence corrupt
255 * the parent process's standard I/O data structures.
256 */
257
258 #if !defined(NTO) && !defined(SYMBIAN)
259 if (attr) {
260 /* the osfd's to redirect stdin, stdout, and stderr to */
261 int in_osfd = -1, out_osfd = -1, err_osfd = -1;
262
263 if (attr->stdinFd
264 && attr->stdinFd->secret->md.osfd != 0) {
265 in_osfd = attr->stdinFd->secret->md.osfd;
266 if (dup2(in_osfd, 0) != 0) {
267 _exit(1); /* failed */
268 }
269 flags = fcntl(0, F_GETFL, 0);
270 if (flags & O_NONBLOCK) {
271 fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
272 }
273 }
274 if (attr->stdoutFd
275 && attr->stdoutFd->secret->md.osfd != 1) {
276 out_osfd = attr->stdoutFd->secret->md.osfd;
277 if (dup2(out_osfd, 1) != 1) {
278 _exit(1); /* failed */
279 }
280 flags = fcntl(1, F_GETFL, 0);
281 if (flags & O_NONBLOCK) {
282 fcntl(1, F_SETFL, flags & ~O_NONBLOCK);
283 }
284 }
285 if (attr->stderrFd
286 && attr->stderrFd->secret->md.osfd != 2) {
287 err_osfd = attr->stderrFd->secret->md.osfd;
288 if (dup2(err_osfd, 2) != 2) {
289 _exit(1); /* failed */
290 }
291 flags = fcntl(2, F_GETFL, 0);
292 if (flags & O_NONBLOCK) {
293 fcntl(2, F_SETFL, flags & ~O_NONBLOCK);
294 }
295 }
296 if (in_osfd != -1) {
297 close(in_osfd);
298 }
299 if (out_osfd != -1 && out_osfd != in_osfd) {
300 close(out_osfd);
301 }
302 if (err_osfd != -1 && err_osfd != in_osfd
303 && err_osfd != out_osfd) {
304 close(err_osfd);
305 }
306 if (attr->currentDirectory) {
307 if (chdir(attr->currentDirectory) < 0) {
308 _exit(1); /* failed */
309 }
310 }
311 }
312
313 if (childEnvp) {
314 (void)execve(path, argv, childEnvp);
315 } else {
316 /* Inherit the environment of the parent. */
317 (void)execv(path, argv);
318 }
319 /* Whoops! It returned. That's a bad sign. */
320 _exit(1);
321 #endif /* !NTO */
322 }
323
324 if (newEnvp) {
325 PR_DELETE(newEnvp);
326 }
327
328 #if defined(_PR_NATIVE_THREADS)
329 PR_Lock(pr_wp.ml);
330 if (0 == pr_wp.numProcs++) {
331 PR_NotifyCondVar(pr_wp.cv);
332 }
333 PR_Unlock(pr_wp.ml);
334 #endif
335 return process;
336 }
337
338 #ifdef _PR_SHARE_CLONES
339
340 struct pr_CreateProcOp {
341 const char *path;
342 char *const *argv;
343 char *const *envp;
344 const PRProcessAttr *attr;
345 PRProcess *process;
346 PRErrorCode prerror;
347 PRInt32 oserror;
348 PRBool done;
349 PRCondVar *doneCV;
350 struct pr_CreateProcOp *next;
351 };
352
353 PRProcess *
354 _MD_CreateUnixProcess(
355 const char *path,
356 char *const *argv,
357 char *const *envp,
358 const PRProcessAttr *attr)
359 {
360 struct pr_CreateProcOp *op;
361 PRProcess *proc;
362 int rv;
363
364 if (PR_CallOnce(&pr_wp.once, _MD_InitProcesses) == PR_FAILURE) {
365 return NULL;
366 }
367
368 op = PR_NEW(struct pr_CreateProcOp);
369 if (NULL == op) {
370 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
371 return NULL;
372 }
373 op->path = path;
374 op->argv = argv;
375 op->envp = envp;
376 op->attr = attr;
377 op->done = PR_FALSE;
378 op->doneCV = PR_NewCondVar(pr_wp.ml);
379 if (NULL == op->doneCV) {
380 PR_DELETE(op);
381 return NULL;
382 }
383 PR_Lock(pr_wp.ml);
384
385 /* add to the tail of op queue */
386 op->next = NULL;
387 if (pr_wp.opTail) {
388 pr_wp.opTail->next = op;
389 pr_wp.opTail = op;
390 } else {
391 PR_ASSERT(NULL == pr_wp.opHead);
392 pr_wp.opHead = pr_wp.opTail = op;
393 }
394
395 /* wake up the daemon thread */
396 do {
397 rv = write(pr_wp.pipefd[1], "", 1);
398 } while (-1 == rv && EINTR == errno);
399
400 while (op->done == PR_FALSE) {
401 PR_WaitCondVar(op->doneCV, PR_INTERVAL_NO_TIMEOUT);
402 }
403 PR_Unlock(pr_wp.ml);
404 PR_DestroyCondVar(op->doneCV);
405 proc = op->process;
406 if (!proc) {
407 PR_SetError(op->prerror, op->oserror);
408 }
409 PR_DELETE(op);
410 return proc;
411 }
412
413 #else /* ! _PR_SHARE_CLONES */
414
415 PRProcess *
416 _MD_CreateUnixProcess(
417 const char *path,
418 char *const *argv,
419 char *const *envp,
420 const PRProcessAttr *attr)
421 {
422 if (PR_CallOnce(&pr_wp.once, _MD_InitProcesses) == PR_FAILURE) {
423 return NULL;
424 }
425 return ForkAndExec(path, argv, envp, attr);
426 } /* _MD_CreateUnixProcess */
427
428 #endif /* _PR_SHARE_CLONES */
429
430 /*
431 * The pid table is a hashtable.
432 *
433 * The number of buckets in the hashtable (NBUCKETS) must be a power of 2.
434 */
435 #define NBUCKETS_LOG2 6
436 #define NBUCKETS (1 << NBUCKETS_LOG2)
437 #define PID_HASH_MASK ((pid_t) (NBUCKETS - 1))
438
439 static pr_PidRecord *
440 FindPidTable(pid_t pid)
441 {
442 pr_PidRecord *pRec;
443 int keyHash = (int) (pid & PID_HASH_MASK);
444
445 pRec = pr_wp.pidTable[keyHash];
446 while (pRec) {
447 if (pRec->pid == pid) {
448 break;
449 }
450 pRec = pRec->next;
451 }
452 return pRec;
453 }
454
455 static void
456 InsertPidTable(pr_PidRecord *pRec)
457 {
458 int keyHash = (int) (pRec->pid & PID_HASH_MASK);
459
460 pRec->next = pr_wp.pidTable[keyHash];
461 pr_wp.pidTable[keyHash] = pRec;
462 }
463
464 static void
465 DeletePidTable(pr_PidRecord *pRec)
466 {
467 int keyHash = (int) (pRec->pid & PID_HASH_MASK);
468
469 if (pr_wp.pidTable[keyHash] == pRec) {
470 pr_wp.pidTable[keyHash] = pRec->next;
471 } else {
472 pr_PidRecord *pred, *cur; /* predecessor and current */
473
474 pred = pr_wp.pidTable[keyHash];
475 cur = pred->next;
476 while (cur) {
477 if (cur == pRec) {
478 pred->next = cur->next;
479 break;
480 }
481 pred = cur;
482 cur = cur->next;
483 }
484 PR_ASSERT(cur != NULL);
485 }
486 }
487
488 static int
489 ExtractExitStatus(int rawExitStatus)
490 {
491 /*
492 * We did not specify the WCONTINUED and WUNTRACED options
493 * for waitpid, so these two events should not be reported.
494 */
495 PR_ASSERT(!WIFSTOPPED(rawExitStatus));
496 #ifdef WIFCONTINUED
497 PR_ASSERT(!WIFCONTINUED(rawExitStatus));
498 #endif
499 if (WIFEXITED(rawExitStatus)) {
500 return WEXITSTATUS(rawExitStatus);
501 } else {
502 PR_ASSERT(WIFSIGNALED(rawExitStatus));
503 return _PR_SIGNALED_EXITSTATUS;
504 }
505 }
506
507 static void
508 ProcessReapedChildInternal(pid_t pid, int status)
509 {
510 pr_PidRecord *pRec;
511
512 pRec = FindPidTable(pid);
513 if (NULL == pRec) {
514 pRec = PR_NEW(pr_PidRecord);
515 pRec->pid = pid;
516 pRec->state = _PR_PID_REAPED;
517 pRec->exitStatus = ExtractExitStatus(status);
518 pRec->reapedCV = NULL;
519 InsertPidTable(pRec);
520 } else {
521 PR_ASSERT(pRec->state != _PR_PID_REAPED);
522 if (_PR_PID_DETACHED == pRec->state) {
523 PR_ASSERT(NULL == pRec->reapedCV);
524 DeletePidTable(pRec);
525 PR_DELETE(pRec);
526 } else {
527 PR_ASSERT(_PR_PID_WAITING == pRec->state);
528 PR_ASSERT(NULL != pRec->reapedCV);
529 pRec->exitStatus = ExtractExitStatus(status);
530 pRec->state = _PR_PID_REAPED;
531 PR_NotifyCondVar(pRec->reapedCV);
532 }
533 }
534 }
535
536 #if defined(_PR_NATIVE_THREADS)
537
538 /*
539 * If all the threads are native threads, the daemon thread is
540 * simpler. We don't need to catch the SIGCHLD signal. We can
541 * just have the daemon thread block in waitpid().
542 */
543
544 static void WaitPidDaemonThread(void *unused)
545 {
546 pid_t pid;
547 int status;
548
549 while (1) {
550 PR_Lock(pr_wp.ml);
551 while (0 == pr_wp.numProcs) {
552 PR_WaitCondVar(pr_wp.cv, PR_INTERVAL_NO_TIMEOUT);
553 }
554 PR_Unlock(pr_wp.ml);
555
556 while (1) {
557 do {
558 pid = waitpid((pid_t) -1, &status, 0);
559 } while ((pid_t) -1 == pid && EINTR == errno);
560
561 /*
562 * waitpid() cannot return 0 because we did not invoke it
563 * with the WNOHANG option.
564 */
565 PR_ASSERT(0 != pid);
566
567 /*
568 * The only possible error code is ECHILD. But if we do
569 * our accounting correctly, we should only call waitpid()
570 * when there is a child process to wait for.
571 */
572 PR_ASSERT((pid_t) -1 != pid);
573 if ((pid_t) -1 == pid) {
574 break;
575 }
576
577 PR_Lock(pr_wp.ml);
578 ProcessReapedChildInternal(pid, status);
579 pr_wp.numProcs--;
580 while (0 == pr_wp.numProcs) {
581 PR_WaitCondVar(pr_wp.cv, PR_INTERVAL_NO_TIMEOUT);
582 }
583 PR_Unlock(pr_wp.ml);
584 }
585 }
586 }
587
588 #else /* _PR_NATIVE_THREADS */
589
590 static void WaitPidDaemonThread(void *unused)
591 {
592 PRPollDesc pd;
593 PRFileDesc *fd;
594 int rv;
595 char buf[128];
596 pid_t pid;
597 int status;
598 #ifdef _PR_SHARE_CLONES
599 struct pr_CreateProcOp *op;
600 #endif
601
602 #ifdef _PR_SHARE_CLONES
603 pr_InstallSigchldHandler();
604 #endif
605
606 fd = PR_ImportFile(pr_wp.pipefd[0]);
607 PR_ASSERT(NULL != fd);
608 pd.fd = fd;
609 pd.in_flags = PR_POLL_READ;
610
611 while (1) {
612 rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
613 PR_ASSERT(1 == rv);
614
615 #ifdef _PR_SHARE_CLONES
616 if (pr_waitpid_daemon_exit) {
617 return;
618 }
619 PR_Lock(pr_wp.ml);
620 #endif
621
622 do {
623 rv = read(pr_wp.pipefd[0], buf, sizeof(buf));
624 } while (sizeof(buf) == rv || (-1 == rv && EINTR == errno));
625
626 #ifdef _PR_SHARE_CLONES
627 PR_Unlock(pr_wp.ml);
628 while ((op = pr_wp.opHead) != NULL) {
629 op->process = ForkAndExec(op->path, op->argv,
630 op->envp, op->attr);
631 if (NULL == op->process) {
632 op->prerror = PR_GetError();
633 op->oserror = PR_GetOSError();
634 }
635 PR_Lock(pr_wp.ml);
636 pr_wp.opHead = op->next;
637 if (NULL == pr_wp.opHead) {
638 pr_wp.opTail = NULL;
639 }
640 op->done = PR_TRUE;
641 PR_NotifyCondVar(op->doneCV);
642 PR_Unlock(pr_wp.ml);
643 }
644 #endif
645
646 while (1) {
647 do {
648 pid = waitpid((pid_t) -1, &status, WNOHANG);
649 } while ((pid_t) -1 == pid && EINTR == errno);
650 if (0 == pid) break;
651 if ((pid_t) -1 == pid) {
652 /* must be because we have no child processes */
653 PR_ASSERT(ECHILD == errno);
654 break;
655 }
656
657 PR_Lock(pr_wp.ml);
658 ProcessReapedChildInternal(pid, status);
659 PR_Unlock(pr_wp.ml);
660 }
661 }
662 }
663
664 static void pr_SigchldHandler(int sig)
665 {
666 int errnoCopy;
667 int rv;
668
669 errnoCopy = errno;
670
671 do {
672 rv = write(pr_wp.pipefd[1], "", 1);
673 } while (-1 == rv && EINTR == errno);
674
675 #ifdef DEBUG
676 if (-1 == rv && EAGAIN != errno && EWOULDBLOCK != errno) {
677 char *msg = "cannot write to pipe\n";
678 write(2, msg, strlen(msg) + 1);
679 _exit(1);
680 }
681 #endif
682
683 errno = errnoCopy;
684 }
685
686 static void pr_InstallSigchldHandler()
687 {
688 #if defined(HPUX) && defined(_PR_DCETHREADS)
689 #error "HP-UX DCE threads have their own SIGCHLD handler"
690 #endif
691
692 struct sigaction act, oact;
693 int rv;
694
695 act.sa_handler = pr_SigchldHandler;
696 sigemptyset(&act.sa_mask);
697 act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
698 rv = sigaction(SIGCHLD, &act, &oact);
699 PR_ASSERT(0 == rv);
700 /* Make sure we are not overriding someone else's SIGCHLD handler */
701 #ifndef _PR_SHARE_CLONES
702 PR_ASSERT(oact.sa_handler == SIG_DFL);
703 #endif
704 }
705
706 #endif /* !defined(_PR_NATIVE_THREADS) */
707
708 static PRStatus _MD_InitProcesses(void)
709 {
710 #if !defined(_PR_NATIVE_THREADS)
711 int rv;
712 int flags;
713 #endif
714
715 #ifdef AIX
716 {
717 void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
718 pr_wp.forkptr = (pid_t (*)(void)) dlsym(handle, "f_fork");
719 if (!pr_wp.forkptr) {
720 pr_wp.forkptr = fork;
721 }
722 dlclose(handle);
723 }
724 #endif /* AIX */
725
726 pr_wp.ml = PR_NewLock();
727 PR_ASSERT(NULL != pr_wp.ml);
728
729 #if defined(_PR_NATIVE_THREADS)
730 pr_wp.numProcs = 0;
731 pr_wp.cv = PR_NewCondVar(pr_wp.ml);
732 PR_ASSERT(NULL != pr_wp.cv);
733 #else
734 rv = pipe(pr_wp.pipefd);
735 PR_ASSERT(0 == rv);
736 flags = fcntl(pr_wp.pipefd[0], F_GETFL, 0);
737 fcntl(pr_wp.pipefd[0], F_SETFL, flags | O_NONBLOCK);
738 flags = fcntl(pr_wp.pipefd[1], F_GETFL, 0);
739 fcntl(pr_wp.pipefd[1], F_SETFL, flags | O_NONBLOCK);
740
741 #ifndef _PR_SHARE_CLONES
742 pr_InstallSigchldHandler();
743 #endif
744 #endif /* !_PR_NATIVE_THREADS */
745
746 pr_wp.thread = PR_CreateThread(PR_SYSTEM_THREAD,
747 WaitPidDaemonThread, NULL, PR_PRIORITY_NORMAL,
748 #ifdef _PR_SHARE_CLONES
749 PR_GLOBAL_THREAD,
750 #else
751 PR_LOCAL_THREAD,
752 #endif
753 PR_JOINABLE_THREAD, 0);
754 PR_ASSERT(NULL != pr_wp.thread);
755
756 pr_wp.pidTable = (pr_PidRecord**)PR_CALLOC(NBUCKETS * sizeof(pr_PidRecord *));
757 PR_ASSERT(NULL != pr_wp.pidTable);
758 return PR_SUCCESS;
759 }
760
761 PRStatus _MD_DetachUnixProcess(PRProcess *process)
762 {
763 PRStatus retVal = PR_SUCCESS;
764 pr_PidRecord *pRec;
765
766 PR_Lock(pr_wp.ml);
767 pRec = FindPidTable(process->md.pid);
768 if (NULL == pRec) {
769 pRec = PR_NEW(pr_PidRecord);
770 if (NULL == pRec) {
771 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
772 retVal = PR_FAILURE;
773 goto done;
774 }
775 pRec->pid = process->md.pid;
776 pRec->state = _PR_PID_DETACHED;
777 pRec->reapedCV = NULL;
778 InsertPidTable(pRec);
779 } else {
780 PR_ASSERT(_PR_PID_REAPED == pRec->state);
781 if (_PR_PID_REAPED != pRec->state) {
782 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
783 retVal = PR_FAILURE;
784 } else {
785 DeletePidTable(pRec);
786 PR_ASSERT(NULL == pRec->reapedCV);
787 PR_DELETE(pRec);
788 }
789 }
790 PR_DELETE(process);
791
792 done:
793 PR_Unlock(pr_wp.ml);
794 return retVal;
795 }
796
797 PRStatus _MD_WaitUnixProcess(
798 PRProcess *process,
799 PRInt32 *exitCode)
800 {
801 pr_PidRecord *pRec;
802 PRStatus retVal = PR_SUCCESS;
803 PRBool interrupted = PR_FALSE;
804
805 PR_Lock(pr_wp.ml);
806 pRec = FindPidTable(process->md.pid);
807 if (NULL == pRec) {
808 pRec = PR_NEW(pr_PidRecord);
809 if (NULL == pRec) {
810 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
811 retVal = PR_FAILURE;
812 goto done;
813 }
814 pRec->pid = process->md.pid;
815 pRec->state = _PR_PID_WAITING;
816 pRec->reapedCV = PR_NewCondVar(pr_wp.ml);
817 if (NULL == pRec->reapedCV) {
818 PR_DELETE(pRec);
819 retVal = PR_FAILURE;
820 goto done;
821 }
822 InsertPidTable(pRec);
823 while (!interrupted && _PR_PID_REAPED != pRec->state) {
824 if (PR_WaitCondVar(pRec->reapedCV,
825 PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE
826 && PR_GetError() == PR_PENDING_INTERRUPT_ERROR) {
827 interrupted = PR_TRUE;
828 }
829 }
830 if (_PR_PID_REAPED == pRec->state) {
831 if (exitCode) {
832 *exitCode = pRec->exitStatus;
833 }
834 } else {
835 PR_ASSERT(interrupted);
836 retVal = PR_FAILURE;
837 }
838 DeletePidTable(pRec);
839 PR_DestroyCondVar(pRec->reapedCV);
840 PR_DELETE(pRec);
841 } else {
842 PR_ASSERT(_PR_PID_REAPED == pRec->state);
843 PR_ASSERT(NULL == pRec->reapedCV);
844 DeletePidTable(pRec);
845 if (exitCode) {
846 *exitCode = pRec->exitStatus;
847 }
848 PR_DELETE(pRec);
849 }
850 PR_DELETE(process);
851
852 done:
853 PR_Unlock(pr_wp.ml);
854 return retVal;
855 } /* _MD_WaitUnixProcess */
856
857 PRStatus _MD_KillUnixProcess(PRProcess *process)
858 {
859 PRErrorCode prerror;
860 PRInt32 oserror;
861
862 #ifdef SYMBIAN
863 /* In Symbian OS, we can not kill other process with Open C */
864 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, oserror);
865 return PR_FAILURE;
866 #else
867 if (kill(process->md.pid, SIGKILL) == 0) {
868 return PR_SUCCESS;
869 }
870 oserror = errno;
871 switch (oserror) {
872 case EPERM:
873 prerror = PR_NO_ACCESS_RIGHTS_ERROR;
874 break;
875 case ESRCH:
876 prerror = PR_INVALID_ARGUMENT_ERROR;
877 break;
878 default:
879 prerror = PR_UNKNOWN_ERROR;
880 break;
881 }
882 PR_SetError(prerror, oserror);
883 return PR_FAILURE;
884 #endif
885 } /* _MD_KillUnixProcess */
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)