blob: 10925c4623656d9a5f66c7b2504137e9eeaa6e00 [file] [log] [blame] [raw]
/* A part of the Native C Library for Windows NT
Copyright 2007-2015 PC GO Ld.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*/
#include <sys/wait.h>
#include <windows.h>
#include <nt.h>
#include <errno.h>
#include <unistd.h>
#include <process.h>
#include <ntstatus.h>
#include <assert.h>
struct child {
//int vaild;
pid_t pid;
void *handle;
};
static struct child child_table[64];
int __child_process_table_add(pid_t pid, void *handle) {
int i = 0;
while(child_table[i].pid > 0) {
if(++i == 64) {
errno = EAGAIN;
return -1;
}
}
child_table[i].pid = pid;
child_table[i].handle = handle;
return 0;
}
// Return index or -1 if not found
static int find_child_by_pid(pid_t pid, void **handle) {
int i;
for(i=0; i<64; i++) {
if(child_table[i].pid == pid) {
*handle = child_table[i].handle;
return i;
}
}
return -1;
}
// Return index or -1 if not found
// Handle not a common pointer type, don't add the const to the argument
static int find_child_by_handle(void *handle, pid_t *pid) {
int i;
for(i=0; i<64; i++) {
if(child_table[i].handle == handle) {
*pid = child_table[i].pid;
return i;
}
}
return -1;
}
static unsigned int find_children(void **handles) {
int count = 0, i;
for(i=0; i<64; i++) {
if(child_table[i].pid > 0) {
handles[count++] = child_table[i].handle;
}
}
return count;
}
pid_t waitpid(pid_t pid, int *status, int options) {
int i;
void *handle;
long int ntstatus;
if(pid == -1) {
void *handles[64];
int count = find_children(handles);
if(!count) {
errno = ECHILD;
return -1;
}
if(options & WNOHANG) return 0;
ntstatus = NtWaitForMultipleObjects(count, handles, WaitAny, 0, NULL);
if(ntstatus < 0) {
__set_errno_from_ntstatus(ntstatus);
return -1;
}
if(ntstatus == STATUS_ALERTED || ntstatus == STATUS_USER_APC) {
errno = EINTR;
return -1;
}
assert(ntstatus < count);
handle = handles[ntstatus];
i = find_child_by_handle(handle, &pid);
assert(i >= 0 && pid > 0);
} else {
if(pid <= 0) {
errno = ENOSYS;
return -1;
}
i = find_child_by_pid(pid, &handle);
if(i == -1) {
errno = ECHILD;
return -1;
}
if(options & WNOHANG) return pid;
ntstatus = NtWaitForSingleObject(handle, 0, NULL);
if(ntstatus < 0) {
__set_errno_from_ntstatus(ntstatus);
return -1;
}
if(ntstatus == STATUS_ALERTED || ntstatus == STATUS_USER_APC) {
errno = EINTR;
return -1;
}
}
child_table[i].pid = -1;
child_table[i].handle = (void *)-1;
if(status) {
PROCESS_BASIC_INFORMATION pbi;
ntstatus = NtQueryInformationProcess(handle, ProcessBasicInformation, &pbi, sizeof pbi, NULL);
if(ntstatus < 0) {
NtClose(handle);
__set_errno_from_ntstatus(ntstatus);
return -1;
}
*status = pbi.ExitStatus;
}
NtClose(handle);
return pid;
}
pid_t wait(int *status) {
return waitpid(-1, status, 0);
}