1/*
2 * Copyright (c) 2011, 2013, 2014, ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <sys/wait.h>
11#include <assert.h>
12#include <errno.h>
13#include <stdio.h>
14#include <barrelfish/barrelfish.h>
15#include <barrelfish/spawn_client.h>
16#include "posixcompat.h"
17
18#define MAX_CHILDREN    64
19
20static pid_t children[MAX_CHILDREN];
21
22int _posixcompat_add_child(pid_t pid);
23
24pid_t wait(int *status)
25{
26    return waitpid(-1, status, 0);
27}
28
29pid_t wait3(int *status, int options, struct rusage *rusage)
30{
31    // XXX: Won't touch rusage at all
32    return waitpid(-1, status, options);
33}
34
35pid_t waitpid(pid_t pid, int *status, int options)
36{
37    int i;
38    bool nohang = options & WNOHANG ? true : false;
39
40    if(pid <= 0) {
41        // XXX: We don't have process groups, so all these cases are the same
42        for(i = 0; i < MAX_CHILDREN; i++) {
43            if(children[i] != 0) {
44                break;
45            }
46        }
47
48        if(i == MAX_CHILDREN) {
49            errno = ECHILD;
50            return -1;
51        }
52    } else {
53        for(i = 0; i < MAX_CHILDREN; i++) {
54            if(children[i] == pid) {
55                break;
56            }
57        }
58
59        if(i == MAX_CHILDREN) {
60            errno = ECHILD;
61            return -1;
62        }
63    }
64
65    if(!nohang && pid <= 0) {
66        printf("Warning: waitpid(<= 0, _, _) waits for the first child, "
67               "not all\n");
68    }
69
70    // We got a child to wait for
71    uint8_t exitcode;
72    errval_t err = spawn_wait_compat(children[i], &exitcode, nohang);
73    if(err_is_fail(err)) {
74        if(err_no(err) == SPAWN_ERR_DOMAIN_RUNNING) {
75            return 0;
76        } else {
77            DEBUG_ERR(err, "spawn_wait");
78        }
79        return -1;
80    }
81
82    *status = exitcode;
83    pid_t wpid = children[i];
84    children[i] = 0;
85
86    POSIXCOMPAT_DEBUG("waitpid(%d, %d, %d) = %d\n",
87                      pid, *status, options, wpid);
88
89    return wpid;
90}
91
92/**
93 * \brief This is a hack to add a child process, while we don't have fork() or exec().
94 */
95int _posixcompat_add_child(pid_t pid)
96{
97    for(int i = 0; i < MAX_CHILDREN; i++) {
98        if(children[i] == 0) {
99            children[i] = pid;
100            return 0;
101        }
102    }
103
104    return -1;
105}
106