Example #1
0
int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * attr) {
    PThreadCond * p = (PThreadCond *)loc_alloc_zero(sizeof(PThreadCond));
    if (attr != NULL) {
        PThreadCondAttr * a = (PThreadCondAttr *)*attr;
        p->clock_id = a->clock_id;
    }
    else {
        p->clock_id = CLOCK_REALTIME;
    }
    p->waiters_count = 0;
    p->was_broadcast = 0;
    p->sema = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
    if (p->sema == NULL) return set_win32_errno(GetLastError());
    InitializeCriticalSection(&p->waiters_count_lock);
    p->waiters_done = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (p->waiters_done == NULL) return set_win32_errno(GetLastError());
    *cond = (pthread_cond_t)p;
    return 0;
}
Example #2
0
static int get_sym_info(const Symbol * sym, DWORD index, SYMBOL_INFO ** res) {
    static ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)];
    SYMBOL_INFO * info = (SYMBOL_INFO *)buffer;
    HANDLE process = get_context_handle(sym->ctx->parent == NULL ? sym->ctx : sym->ctx->parent);

    info->SizeOfStruct = sizeof(SYMBOL_INFO);
    info->MaxNameLen = MAX_SYM_NAME;
    if (!SymFromIndex(process, sym->module, index, info)) {
        set_win32_errno(GetLastError());
        return -1;
    }
    *res = info;
    return 0;
}
Example #3
0
int pthread_cond_signal(pthread_cond_t * cond) {
    int have_waiters = 0;
    PThreadCond * p = (PThreadCond *)*cond;

    EnterCriticalSection(&p->waiters_count_lock);
    have_waiters = p->waiters_count > 0;
    LeaveCriticalSection(&p->waiters_count_lock);

    /* If there aren't any waiters, then this is a no-op.   */
    if (have_waiters) {
        if (!ReleaseSemaphore(p->sema, 1, 0)) return set_win32_errno(GetLastError());
    }
    return 0;
}
Example #4
0
int enumerate_symbols(Context * ctx, int frame, EnumerateSymbolsCallBack * call_back, void * args) {
    ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)];
    SYMBOL_INFO * symbol = (SYMBOL_INFO *)buffer;
    IMAGEHLP_STACK_FRAME stack_frame;
    EnumerateSymbolsContext enum_context;
    HANDLE process = get_context_handle(ctx->parent == NULL ? ctx : ctx->parent);

    symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
    symbol->MaxNameLen = MAX_SYM_NAME;

    if (frame == STACK_TOP_FRAME) frame = get_top_frame(ctx);
    if (frame == STACK_TOP_FRAME) return -1;
    if (get_stack_frame(ctx, frame, 0, &stack_frame) < 0) return -1;

    if (!SymSetContext(process, &stack_frame, NULL)) {
        DWORD err = GetLastError();
        if (err == ERROR_SUCCESS) {
            /* Don't know why Windows does that */
        }
        else {
            set_win32_errno(err);
            return -1;
        }
    }

    enum_context.ctx = ctx;
    enum_context.frame = frame;
    enum_context.call_back = call_back;
    enum_context.args = args;

    if (!SymEnumSymbols(process, 0, NULL, enumerate_symbols_proc, &enum_context)) {
        set_win32_errno(GetLastError());
        return -1;
    }

    return 0;
}
Example #5
0
static int find_pe_symbol_by_addr(Context * ctx, int frame, ContextAddress addr, Symbol * sym) {
    HANDLE process = get_context_handle(ctx->parent == NULL ? ctx : ctx->parent);
    ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)];
    SYMBOL_INFO * info = (SYMBOL_INFO *)buffer;
    IMAGEHLP_STACK_FRAME stack_frame;
    DWORD err;

    if (set_pe_context(ctx, frame, 0, process, &stack_frame) < 0) return -1;

    memset(info, 0, sizeof(SYMBOL_INFO));
    info->SizeOfStruct = sizeof(SYMBOL_INFO);
    info->MaxNameLen = MAX_SYM_NAME;

    if (SymFromAddr(process, addr, NULL, info)) {
        syminfo2symbol(ctx, frame, info, sym);
        return 0;
    }

    set_win32_errno(err = GetLastError());
    if (err == 0 || err == ERROR_MOD_NOT_FOUND || err == ERROR_INVALID_ADDRESS) {
        errno = ERR_SYM_NOT_FOUND;
    }
    return -1;
}
Example #6
0
static int find_pe_symbol_by_name(Context * ctx, int frame, ContextAddress ip, char * name, Symbol * sym) {
    HANDLE process = get_context_handle(ctx->parent == NULL ? ctx : ctx->parent);
    ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)];
    SYMBOL_INFO * info = (SYMBOL_INFO *)buffer;
    IMAGEHLP_STACK_FRAME stack_frame;
    DWORD err;

    if (set_pe_context(ctx, frame, ip, process, &stack_frame) < 0) return -1;

    memset(info, 0, sizeof(SYMBOL_INFO));
    info->SizeOfStruct = sizeof(SYMBOL_INFO);
    info->MaxNameLen = MAX_SYM_NAME;

    if (find_cache_symbol(ctx, frame, stack_frame.InstructionOffset, name, sym)) return errno ? -1 : 0;

    /* TODO: SymFromName() searches only main executable, need to search DLLs too */
    if (SymFromName(process, name, info) && info->Tag != SymTagPublicSymbol) {
        syminfo2symbol(ctx, frame, info, sym);
        add_cache_symbol(ctx, stack_frame.InstructionOffset, name, sym, 0);
        return 0;
    }
    if (stack_frame.InstructionOffset != 0) {
        DWORD64 module = SymGetModuleBase64(process, stack_frame.InstructionOffset);
        if (module != 0 && SymGetTypeFromName(process, module, name, info)) {
            syminfo2symbol(ctx, frame, info, sym);
            add_cache_symbol(ctx, stack_frame.InstructionOffset, name, sym, 0);
            return 0;
        }
    }
    set_win32_errno(err = GetLastError());
    if (err == 0 || err == ERROR_MOD_NOT_FOUND) {
        add_cache_symbol(ctx, stack_frame.InstructionOffset, name, NULL, ERR_SYM_NOT_FOUND);
        errno = ERR_SYM_NOT_FOUND;
    }
    return -1;
}
Example #7
0
int run_test_process(ContextAttachCallBack * done, void * data) {
#if defined(_WIN32)
    char fnm[FILE_PATH_SIZE];
    char cmd[FILE_PATH_SIZE];
    int res = 0;
    STARTUPINFO si;
    PROCESS_INFORMATION prs;
    ContextAttachArgs * args;

    memset(&si, 0, sizeof(si));
    memset(&prs, 0, sizeof(prs));
    memset(fnm, 0, sizeof(fnm));
    if (GetModuleFileName(NULL, fnm, sizeof(fnm)) == 0) {
        set_win32_errno(GetLastError());
        return -1;
    }
    si.cb = sizeof(si);
    strcpy(cmd, "agent.exe -t");
    if (CreateProcess(fnm, cmd, NULL, NULL,
            FALSE, CREATE_SUSPENDED | CREATE_DEFAULT_ERROR_MODE | CREATE_NO_WINDOW,
            NULL, NULL, &si, &prs) == 0) {
        set_win32_errno(GetLastError());
        return -1;
    }
    args = (ContextAttachArgs *)loc_alloc(sizeof(ContextAttachArgs));
    args->done = done;
    args->data = data;
    args->thread = prs.hThread;
    args->process = prs.hProcess;
    res = context_attach(prs.dwProcessId, done_context_attach, args, 0);
    if (res != 0) loc_free(args);
    return res;
#elif defined(_WRS_KERNEL)
    int tid = taskCreate("tTcf", 100, 0, 0x4000, (FUNCPTR)test_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    if (tid == 0) return -1;
    taskStop(tid);
    taskActivate(tid);
    assert(taskIsStopped(tid));
    return context_attach(tid, done, data, 0);
#else
    int pid = fork();
    if (pid < 0) return -1;
    if (pid == 0) {
        int fd = sysconf(_SC_OPEN_MAX);
        while (fd > 3) close(--fd);
        if (context_attach_self() < 0) exit(1);
#if defined(__linux__)
        {
            char buf[32];
            char * fnm = NULL;
            snprintf(buf, sizeof(buf), "/proc/%d/exe", getpid());
            fnm = canonicalize_file_name(buf);
            if (fnm != NULL) execl(fnm, fnm, "-t", (char *)NULL);
            exit(1);
        }
#else
        {
            if (tkill(getpid(), SIGSTOP) < 0) exit(1);
            test_proc();
            exit(0);
        }
#endif
    }
    return context_attach(pid, done, data, CONTEXT_ATTACH_SELF);
#endif
}
Example #8
0
int get_symbol_name(const Symbol * sym, char ** name) {
    WCHAR * ptr = NULL;

    assert(sym->magic == SYMBOL_MAGIC);
    if (sym->base) {
        *name = NULL;
        return 0;
    }
    if (sym->info) {
        *name = sym->info->name;
        return 0;
    }
    *name = NULL;
    if (get_type_info(sym, TI_GET_SYMNAME, &ptr) < 0) ptr = NULL;
    if (ptr != NULL && wcscmp(ptr, L"<unnamed-tag>") == 0) ptr = NULL;
    if (ptr != NULL) {
        int len = 0;
        int err = 0;
        if (tmp_buf == NULL) {
            tmp_buf_size = 256;
            tmp_buf = (char *)loc_alloc(tmp_buf_size);
        }
        for (;;) {
            len = WideCharToMultiByte(CP_UTF8, 0, ptr, -1, tmp_buf, tmp_buf_size - 1, NULL, NULL);
            if (len != 0) break;
            err = GetLastError();
            if (err != ERROR_INSUFFICIENT_BUFFER) {
                set_win32_errno(err);
                return -1;
            }
            tmp_buf_size *= 2;
            tmp_buf = (char *)loc_realloc(tmp_buf, tmp_buf_size);
        }
        HeapFree(GetProcessHeap(), 0, ptr);
        tmp_buf[len] = 0;
        *name = tmp_buf;
    }
    else {
        DWORD tag = 0;
        Symbol type = *sym;
        if (get_type_tag(&type, &tag)) return -1;
        if (tag == SymTagBaseType) {
            ContextAddress size = 0;
            int type_class = 0;
            unsigned char sign = 0;
            unsigned char real = 0;
            const TypeInfo * p = basic_type_info;
            if (get_symbol_size(&type, &size)) return -1;
            if (get_symbol_type_class(&type, &type_class)) return -1;
            if (type_class == TYPE_CLASS_INTEGER) sign = 1;
            else if (type_class == TYPE_CLASS_REAL) real = sign = 1;
            while (p->name != NULL) {
                if (p->size == size && p->sign == sign && p->real == real) {
                    *name = p->name;
                    break;
                }
                p++;
            }
        }
    }
    return 0;
}
Example #9
0
int pthread_mutex_unlock(pthread_mutex_t * mutex) {
    assert(mutex != NULL);
    assert(*mutex != NULL);
    if (!ReleaseMutex(*mutex)) return set_win32_errno(GetLastError());
    return 0;
}
Example #10
0
int pthread_mutex_destroy(pthread_mutex_t * mutex) {
    assert(mutex != NULL);
    assert(*mutex != NULL);
    if (!CloseHandle(*mutex)) return set_win32_errno(GetLastError());
    return 0;
}
Example #11
0
int pthread_mutex_lock(pthread_mutex_t * mutex) {
    assert(mutex != NULL);
    assert(*mutex != NULL);
    if (WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED) return set_win32_errno(GetLastError());
    return 0;
}
Example #12
0
int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t * attr) {
    assert(attr == NULL);
    *mutex = (pthread_mutex_t)CreateMutex(NULL, FALSE, NULL);
    if (*mutex == NULL) return set_win32_errno(GetLastError());
    return 0;
}
Example #13
0
static void * worker_thread_handler(void * x) {
    WorkerThread * wt = (WorkerThread *)x;

    for (;;) {
        AsyncReqInfo * req = wt->req;

        assert(req != NULL);
        req->error = 0;
        switch(req->type) {
        case AsyncReqTimer:
#if defined(_WIN32) && !defined(__CYGWIN__)
            Sleep(EVENTS_TIMER_RESOLUTION);
            events_timer_ms = GetTickCount();
#else
            {
                struct timespec timenow;
                usleep(EVENTS_TIMER_RESOLUTION * 1000);
                if (clock_gettime(CLOCK_REALTIME, &timenow) == 0) {
                    events_timer_ms = (uint32_t)(timenow.tv_nsec / 1000000 + timenow.tv_sec * 1000);
                }
            }
#endif
            break;

        case AsyncReqRead:              /* File read */
            req->u.fio.rval = read(req->u.fio.fd, req->u.fio.bufp, req->u.fio.bufsz);
            if (req->u.fio.rval == -1) {
                req->error = errno;
                assert(req->error);
            }
            break;

        case AsyncReqWrite:             /* File write */
            req->u.fio.rval = write(req->u.fio.fd, req->u.fio.bufp, req->u.fio.bufsz);
            if (req->u.fio.rval == -1) {
                req->error = errno;
                assert(req->error);
            }
            break;

        case AsyncReqSeekRead:          /* File read at offset */
            req->u.fio.rval = pread(req->u.fio.fd, req->u.fio.bufp, req->u.fio.bufsz, (off_t)req->u.fio.offset);
            if (req->u.fio.rval == -1) {
                req->error = errno;
                assert(req->error);
            }
            break;

        case AsyncReqSeekWrite:         /* File write at offset */
            req->u.fio.rval = pwrite(req->u.fio.fd, req->u.fio.bufp, req->u.fio.bufsz, (off_t)req->u.fio.offset);
            if (req->u.fio.rval == -1) {
                req->error = errno;
                assert(req->error);
            }
            break;

        case AsyncReqRecv:              /* Socket recv */
            req->u.sio.rval = recv(req->u.sio.sock, req->u.sio.bufp, req->u.sio.bufsz, req->u.sio.flags);
            if (req->u.sio.rval == -1) {
                req->error = errno;
                assert(req->error);
            }
            break;

        case AsyncReqSend:              /* Socket send */
            req->u.sio.rval = send(req->u.sio.sock, req->u.sio.bufp, req->u.sio.bufsz, req->u.sio.flags);
            if (req->u.sio.rval == -1) {
                req->error = errno;
                assert(req->error);
            }
            break;

        case AsyncReqRecvFrom:          /* Socket recvfrom */
            req->u.sio.rval = recvfrom(req->u.sio.sock, req->u.sio.bufp, req->u.sio.bufsz, req->u.sio.flags, req->u.sio.addr, &req->u.sio.addrlen);
            if (req->u.sio.rval == -1) {
                req->error = errno;
                trace(LOG_ASYNCREQ, "AsyncReqRecvFrom: req %p, type %d, error %d", req, req->type, req->error);
                assert(req->error);
            }
            break;

        case AsyncReqSendTo:            /* Socket sendto */
            req->u.sio.rval = sendto(req->u.sio.sock, req->u.sio.bufp, req->u.sio.bufsz, req->u.sio.flags, req->u.sio.addr, req->u.sio.addrlen);
            if (req->u.sio.rval == -1) {
                req->error = errno;
                assert(req->error);
            }
            break;

        case AsyncReqAccept:            /* Accept socket connections */
            req->u.acc.rval = accept(req->u.acc.sock, req->u.acc.addr, req->u.acc.addr ? &req->u.acc.addrlen : NULL);
            if (req->u.acc.rval == -1) {
                req->error = errno;
                trace(LOG_ASYNCREQ, "AsyncReqAccept: req %p, type %d, error %d", req, req->type, req->error);
                assert(req->error);
            }
            break;

        case AsyncReqConnect:           /* Connect to socket */
            req->u.con.rval = connect(req->u.con.sock, req->u.con.addr, req->u.con.addrlen);
            if (req->u.con.rval == -1) {
                req->error = errno;
                trace(LOG_ASYNCREQ, "AsyncReqConnect: req %p, type %d, error %d", req, req->type, req->error);
                assert(req->error);
            }
            break;

/* Platform dependant IO methods */
#if defined(_WIN32) || defined(__CYGWIN__)
        case AsyncReqConnectPipe:
            req->u.cnp.rval = ConnectNamedPipe(req->u.cnp.pipe, NULL);
            if (!req->u.cnp.rval) {
                req->error = set_win32_errno(GetLastError());
                assert(req->error);
            }
            break;
#elif defined(_WRS_KERNEL)
#else
        case AsyncReqWaitpid:           /* Wait for process change */
            req->u.wpid.rval = waitpid(req->u.wpid.pid, &req->u.wpid.status, req->u.wpid.options);
            if (req->u.wpid.rval == -1) {
                req->error = errno;
                assert(req->error);
            }
            break;
#endif

        case AsyncReqSelect:
            {
                struct timeval tv;
                tv.tv_sec = (long)req->u.select.timeout.tv_sec;
                tv.tv_usec = req->u.select.timeout.tv_nsec / 1000;
                req->u.select.rval = select(req->u.select.nfds, &req->u.select.readfds,
                            &req->u.select.writefds, &req->u.select.errorfds, &tv);
                if (req->u.select.rval == -1) {
                    req->error = errno;
                    assert(req->error);
                }
            }
            break;

        case AsyncReqClose:
            req->u.fio.rval = close(req->u.fio.fd);
            if (req->u.fio.rval == -1) {
                req->error = errno;
                assert(req->error);
            }
            break;

        case AsyncReqCloseDir:
            req->u.dio.rval = closedir((DIR *)req->u.dio.dir);
            if (req->u.dio.rval == -1) {
                req->error = errno;
                assert(req->error);
            }
            break;

        case AsyncReqOpen:
            req->u.fio.rval = open(req->u.fio.file_name, req->u.fio.flags, req->u.fio.permission);
            if (req->u.fio.rval == -1) {
                req->error = errno;
                assert(req->error);
            }
            break;

        case AsyncReqOpenDir:
            req->u.dio.dir = opendir(req->u.dio.path);
            if (req->u.dio.dir == NULL) {
                req->error = errno;
                assert(req->error);
            }
            break;

        case AsyncReqFstat:
            memset(&req->u.fio.statbuf, 0, sizeof(req->u.fio.statbuf));
            req->u.fio.rval = fstat(req->u.fio.fd, &req->u.fio.statbuf);
            if (req->u.fio.rval == -1) {
                req->error = errno;
                assert(req->error);
            }
#if defined(_WIN32) || defined(__CYGWIN__)
            req->u.fio.win32_attrs = req->error || !req->u.fio.file_name ?
                INVALID_FILE_ATTRIBUTES : GetFileAttributes(req->u.fio.file_name);
#endif
            break;

        case AsyncReqStat:
            memset(&req->u.fio.statbuf, 0, sizeof(req->u.fio.statbuf));
            req->u.fio.rval = stat(req->u.fio.file_name, &req->u.fio.statbuf);
            if (req->u.fio.rval == -1) {
                req->error = errno;
                assert(req->error);
            }
#if defined(_WIN32) || defined(__CYGWIN__)
            req->u.fio.win32_attrs = req->error ?
                INVALID_FILE_ATTRIBUTES : GetFileAttributes(req->u.fio.file_name);
#endif
            break;

        case AsyncReqLstat:
            memset(&req->u.fio.statbuf, 0, sizeof(req->u.fio.statbuf));
            req->u.fio.rval = lstat(req->u.fio.file_name, &req->u.fio.statbuf);
            if (req->u.fio.rval == -1) {
                req->error = errno;
                assert(req->error);
            }
#if defined(_WIN32) || defined(__CYGWIN__)
            req->u.fio.win32_attrs = req->error ?
                INVALID_FILE_ATTRIBUTES : GetFileAttributes(req->u.fio.file_name);
#endif
            break;

        case AsyncReqSetStat:
            {
                int err = 0;
                if (req->u.fio.set_stat_flags & AsyncReqSetSize) {
                    if (truncate(req->u.fio.file_name, (off_t)req->u.fio.statbuf.st_size) < 0) err = errno;
                }
                if (req->u.fio.set_stat_flags & AsyncReqSetPermissions) {
                    if (chmod(req->u.fio.file_name, req->u.fio.statbuf.st_mode) < 0) err = errno;
                }
#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WRS_KERNEL)
#  if defined(_WIN32) || defined(__CYGWIN__)
                if (req->u.fio.win32_attrs != INVALID_FILE_ATTRIBUTES) {
                    if (SetFileAttributes(req->u.fio.file_name, req->u.fio.win32_attrs) == 0)
                        err = set_win32_errno(GetLastError());
                }
#  endif
#else
                if (req->u.fio.set_stat_flags & AsyncReqSetUidGid) {
                    if (chown(req->u.fio.file_name, req->u.fio.statbuf.st_uid, req->u.fio.statbuf.st_gid) < 0) err = errno;
                }
#endif
                if (req->u.fio.set_stat_flags & AsyncReqSetAcModTime) {
                    struct utimbuf buf;
                    buf.actime = req->u.fio.statbuf.st_atime;
                    buf.modtime = req->u.fio.statbuf.st_mtime;
                    if (utime(req->u.fio.file_name, &buf) < 0) err = errno;
                }
                req->error = err;
            }
            break;

        case AsyncReqFSetStat:
            {
                int err = 0;
                if (req->u.fio.set_stat_flags & AsyncReqSetSize) {
                    if (ftruncate(req->u.fio.fd, (off_t)req->u.fio.statbuf.st_size) < 0) err = errno;
                }
#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WRS_KERNEL)
                if (req->u.fio.set_stat_flags & AsyncReqSetPermissions) {
                    if (chmod(req->u.fio.file_name, req->u.fio.statbuf.st_mode) < 0) err = errno;
                }
#  if defined(_WIN32) || defined(__CYGWIN__)
                if (req->u.fio.win32_attrs != INVALID_FILE_ATTRIBUTES) {
                    if (SetFileAttributes(req->u.fio.file_name, req->u.fio.win32_attrs) == 0)
                        err = set_win32_errno(GetLastError());
                }
#  endif
#else
                if (req->u.fio.set_stat_flags & AsyncReqSetUidGid) {
                    if (fchown(req->u.fio.fd, req->u.fio.statbuf.st_uid, req->u.fio.statbuf.st_gid) < 0) err = errno;
                }
                if (req->u.fio.set_stat_flags & AsyncReqSetPermissions) {
                    if (fchmod(req->u.fio.fd, req->u.fio.statbuf.st_mode) < 0) err = errno;
                }
#endif
                if (req->u.fio.set_stat_flags & AsyncReqSetAcModTime) {
                    struct utimbuf buf;
                    buf.actime = req->u.fio.statbuf.st_atime;
                    buf.modtime = req->u.fio.statbuf.st_mtime;
#if defined(_WIN32) && !defined(__MINGW32__)
                    if (futime(req->u.fio.fd, &buf) < 0) err = errno;
#else
                    if (utime(req->u.fio.file_name, &buf) < 0) err = errno;
#endif
                }
                req->error = err;
            }
            break;

        case AsyncReqRemove:
            req->u.fio.rval = remove(req->u.fio.file_name);
            if (req->u.fio.rval == -1) {
                req->error = errno;
                assert(req->error);
            }
            break;

        case AsyncReqReadDir:
            {
                int cnt = 0;
                while (cnt < req->u.dio.max_files) {
                    char path[FILE_PATH_SIZE];
                    struct DirFileNode * file = req->u.dio.files + cnt;
                    struct dirent * e;
                    struct stat st;
                    errno = 0;
                    e = readdir((DIR *)req->u.dio.dir);
                    if (e == NULL) {
                        req->error = errno;
                        if (req->error == 0) req->u.dio.eof = 1;
                        break;
                    }
                    if (strcmp(e->d_name, ".") == 0) continue;
                    if (strcmp(e->d_name, "..") == 0) continue;
                    file->path = loc_strdup(e->d_name);
                    memset(&st, 0, sizeof(st));
                    snprintf(path, sizeof(path), "%s/%s", req->u.dio.path, e->d_name);
                    if (stat(path, &st) == 0) {
#if defined(_WIN32) || defined(__CYGWIN__)
                        file->win32_attrs =  GetFileAttributes(path);
#endif
                        file->statbuf = (struct stat *)loc_alloc(sizeof(struct stat));
                        memcpy(file->statbuf, &st, sizeof(struct stat));
                    }
                    cnt++;
                }
            }
            break;

        case AsyncReqRoots:
            {
                struct stat st;
                struct RootDevNode * newDevNode = NULL;

#if defined(_WIN32) || defined(__CYGWIN__)
                {
                    struct RootDevNode * curDevNode = NULL;
                    int disk = 0;
                    DWORD disks = GetLogicalDrives();
                    for (disk = 0; disk <= 30; disk++) {
                        if (disks & (1 << disk)) {
                            char path[32];
                            newDevNode = (struct RootDevNode *)loc_alloc_zero(sizeof(struct RootDevNode));
                            if (curDevNode == NULL) req->u.root.lst = newDevNode;
                            else curDevNode->next = newDevNode;
                            curDevNode = newDevNode;
                            snprintf(path, sizeof(path), "%c:\\", 'A' + disk);
                            newDevNode->devname = loc_strdup(path);
                            if (disk >= 2) {
                                ULARGE_INTEGER total_number_of_bytes;
                                BOOL has_size = GetDiskFreeSpaceExA(path, NULL, &total_number_of_bytes, NULL);
                                memset(&st, 0, sizeof(st));
#if defined(__CYGWIN__)
                                snprintf(path, sizeof(path), "/cygdrive/%c", 'a' + disk);
#endif
                                if (has_size && stat(path, &st) == 0) {
                                    newDevNode->win32_attrs =  GetFileAttributes(path);
                                    newDevNode->statbuf = (struct stat *)loc_alloc_zero(sizeof(struct stat));
                                    memcpy(newDevNode->statbuf, &st, sizeof(struct stat));
                                }
                            }
                        }
                    }
                }
#elif defined(_WRS_KERNEL)
                {
                    struct RootDevNode * curDevNode = NULL;
                    extern DL_LIST iosDvList;
                    DEV_HDR * dev;
                    for (dev = (DEV_HDR *)DLL_FIRST(&iosDvList); dev != NULL; dev = (DEV_HDR *)DLL_NEXT(&dev->node)) {
                        char path[FILE_PATH_SIZE];
                        if (strcmp(dev->name, "host:") == 0) {
                            /* Windows host is special case */
                            int d;
                            for (d = 'a'; d < 'z'; d++) {
                                snprintf(path, sizeof(path), "%s%c:/", dev->name, d);
                                if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
                                    newDevNode = (struct RootDevNode *)loc_alloc_zero(sizeof(struct RootDevNode));
                                    if (curDevNode == NULL) req->u.root.lst = newDevNode;
                                    else curDevNode->next = newDevNode;
                                    curDevNode = newDevNode;

                                    newDevNode->devname = loc_strdup(path);
                                    newDevNode->statbuf = (struct stat *)loc_alloc_zero(sizeof(struct stat));
                                    memcpy(newDevNode->statbuf, &st, sizeof(struct stat));
                                }
                            }
                        }
                        snprintf(path, sizeof(path), "%s/", dev->name);
                        if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
                            newDevNode = (struct RootDevNode *)loc_alloc_zero(sizeof(struct RootDevNode));
                            if (curDevNode == NULL) req->u.root.lst = newDevNode;
                            else curDevNode->next = newDevNode;
                            curDevNode = newDevNode;

                            newDevNode->devname = loc_strdup(path);
                            newDevNode->statbuf = (struct stat *)loc_alloc_zero(sizeof(struct stat));
                            memcpy(newDevNode->statbuf, &st, sizeof(struct stat));
                        }
                    }
                }
#else
                req->u.root.lst = newDevNode = (struct RootDevNode *)loc_alloc_zero(sizeof(struct RootDevNode));
                newDevNode->devname = loc_strdup("/");
                if (stat("/", &st) == 0) {
                    newDevNode->statbuf = (struct stat *)loc_alloc_zero(sizeof(struct stat));
                    memcpy(newDevNode->statbuf, &st, sizeof(struct stat));
                }
#endif
            }
            break;

        case AsyncReqUser:              /* User defined request */
            req->u.user.rval = req->u.user.func(req->u.user.data);
            if (req->u.user.rval == -1) {
                req->error = errno;
                assert(req->error);
            }
            break;

        default:
            req->error = ENOSYS;
            break;
        }
        if (req->type == AsyncReqTimer) {
            if (async_shutdown.state == SHUTDOWN_STATE_PENDING) break;
            continue;
        }
        trace(LOG_ASYNCREQ, "async_req_complete: req %p, type %d, error %d", req, req->type, req->error);
        check_error(pthread_mutex_lock(&wtlock));
        /* Post event inside lock to make sure a new worker thread is not created unnecessarily */
        post_event(req->done, req);
        wt->req = NULL;
        if (wtlist_size >= MAX_WORKER_THREADS || async_shutdown.state == SHUTDOWN_STATE_PENDING) {
            check_error(pthread_mutex_unlock(&wtlock));
            break;
        }
        list_add_last(&wt->wtlink, &wtlist);
        wtlist_size++;
        for (;;) {
            check_error(pthread_cond_wait(&wt->cond, &wtlock));
            if (wt->req != NULL) break;
        }
        check_error(pthread_mutex_unlock(&wtlock));
        if (wt->req == &shutdown_req) break;
    }
    post_event(worker_thread_exit, wt);
    return NULL;
}
static int start_process(Channel * c, char ** envp, char * dir, char * exe, char ** args, int attach,
                int * pid, int * selfattach, ChildProcess ** prs) {
    typedef struct _SYSTEM_HANDLE_INFORMATION {
        ULONG Count;
        struct HANDLE_INFORMATION {
            USHORT ProcessId;
            USHORT CreatorBackTraceIndex;
            UCHAR ObjectTypeNumber;
            UCHAR Flags;
            USHORT Handle;
            PVOID Object;
            ACCESS_MASK GrantedAccess;
        } Handles[1];
    } SYSTEM_HANDLE_INFORMATION;
    FARPROC QuerySystemInformationProc = GetProcAddress(GetModuleHandle("NTDLL.DLL"), "NtQuerySystemInformation");
    DWORD size;
    NTSTATUS status;
    SYSTEM_HANDLE_INFORMATION * hi = NULL;
    int fpipes[3][2];
    HANDLE hpipes[3][2];
    char * cmd = NULL;
    int err = 0;
    int i;

    if (args != NULL) {
        int i = 0;
        int cmd_size = 0;
        int cmd_pos = 0;
#           define cmd_append(ch) { \
            if (!cmd) { \
                cmd_size = 0x1000; \
                cmd = (char *)loc_alloc(cmd_size); \
            } \
            else if (cmd_pos >= cmd_size) { \
                char * tmp = (char *)loc_alloc(cmd_size * 2); \
                memcpy(tmp, cmd, cmd_pos); \
                loc_free(cmd); \
                cmd = tmp; \
                cmd_size *= 2; \
            }; \
            cmd[cmd_pos++] = (ch); \
        }
        while (args[i] != NULL) {
            char * p = args[i++];
            if (cmd_pos > 0) cmd_append(' ');
            cmd_append('"');
            while (*p) {
                if (*p == '"') cmd_append('\\');
                cmd_append(*p);
                p++;
            }
            cmd_append('"');
        }
        cmd_append(0);
#       undef cmd_append
    }

    size = sizeof(SYSTEM_HANDLE_INFORMATION) * 16;
    hi = loc_alloc(size);
    for (;;) {
        status = QuerySystemInformationProc(SystemHandleInformation, hi, size, &size);
        if (status != STATUS_INFO_LENGTH_MISMATCH) break;
        hi = loc_realloc(hi, size);
    }
    if (status == 0) {
        ULONG i;
        DWORD id = GetCurrentProcessId();
        for (i = 0; i < hi->Count; i++) {
            if (hi->Handles[i].ProcessId != id) continue;
            SetHandleInformation((HANDLE)(int)hi->Handles[i].Handle, HANDLE_FLAG_INHERIT, FALSE);
        }
    }
    else {
        err = set_win32_errno(status);
        trace(LOG_ALWAYS, "Can't start process '%s': %s", exe, errno_to_str(err));
    }
    loc_free(hi);

    memset(hpipes, 0, sizeof(hpipes));
    for (i = 0; i < 3; i++) fpipes[i][0] = fpipes[i][1] = -1;
    if (!err) {
#if defined(__CYGWIN__)
        for (i = 0; i < 3; i++) {
            if (pipe(fpipes[i]) < 0) {
                err = errno;
                break;
            }
            hpipes[i][0] = (HANDLE)get_osfhandle(fpipes[i][0]);
            hpipes[i][1] = (HANDLE)get_osfhandle(fpipes[i][1]);
        }
#else
        for (i = 0; i < 3; i++) {
            if (!CreatePipe(&hpipes[i][0], &hpipes[i][1], NULL, PIPE_SIZE)) {
                err = set_win32_errno(GetLastError());
                break;
            }
            fpipes[i][0] = _open_osfhandle((intptr_t)hpipes[i][0], O_TEXT);
            fpipes[i][1] = _open_osfhandle((intptr_t)hpipes[i][1], O_TEXT);
        }
#endif
    }
    if (!err) {
        STARTUPINFO si;
        PROCESS_INFORMATION prs_info;
        SetHandleInformation(hpipes[0][0], HANDLE_FLAG_INHERIT, TRUE);
        SetHandleInformation(hpipes[1][1], HANDLE_FLAG_INHERIT, TRUE);
        SetHandleInformation(hpipes[2][1], HANDLE_FLAG_INHERIT, TRUE);
        memset(&si, 0, sizeof(si));
        memset(&prs_info, 0, sizeof(prs_info));
        si.cb = sizeof(si);
        si.dwFlags |= STARTF_USESTDHANDLES;
        si.hStdInput  = hpipes[0][0];
        si.hStdOutput = hpipes[1][1];
        si.hStdError  = hpipes[2][1];
        if (CreateProcess(exe, cmd, NULL, NULL, TRUE, (attach ? CREATE_SUSPENDED : 0),
                (envp ? envp[0] : NULL), (dir[0] ? dir : NULL), &si, &prs_info) == 0)
        {
            err = set_win32_errno(GetLastError());
        }
        else {
            *pid = prs_info.dwProcessId;
            CloseHandle(prs_info.hThread);
            CloseHandle(prs_info.hProcess);
        }
    }
    close(fpipes[0][0]);
    close(fpipes[1][1]);
    close(fpipes[2][1]);
    if (!err) {
        *prs = loc_alloc_zero(sizeof(ChildProcess));
        (*prs)->inp = fpipes[0][1];
        (*prs)->out = fpipes[1][0];
        (*prs)->err = fpipes[2][0];
        (*prs)->pid = *pid;
        (*prs)->bcg = c->bcg;
        list_add_first(&(*prs)->link, &prs_list);
    }
    else {
        close(fpipes[0][1]);
        close(fpipes[1][0]);
        close(fpipes[2][0]);
    }
    loc_free(cmd);
    if (!err) return 0;
    trace(LOG_ALWAYS, "Can't start process '%s': %s", exe, errno_to_str(err));
    errno = err;
    return -1;
}
static void command_get_children(char * token, Channel * c) {
    char id[256];
    int attached_only;

    json_read_string(&c->inp, id, sizeof(id));
    if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
    attached_only = json_read_boolean(&c->inp);
    if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
    if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);

    write_stringz(&c->out, "R");
    write_stringz(&c->out, token);

    if (id[0] != 0) {
        write_errno(&c->out, 0);
        write_stringz(&c->out, "null");
    }
    else {
#if defined(WIN32)
    DWORD err = 0;
    HANDLE snapshot;
    PROCESSENTRY32 pe32;

    snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot == INVALID_HANDLE_VALUE) err = set_win32_errno(GetLastError());
    memset(&pe32, 0, sizeof(pe32));
    pe32.dwSize = sizeof(PROCESSENTRY32);
    if (!err && !Process32First(snapshot, &pe32)) {
        err = set_win32_errno(GetLastError());
        CloseHandle(snapshot);
    }
    write_errno(&c->out, err);
    if (err) {
        write_stringz(&c->out, "null");
    }
    else {
        int cnt = 0;
        write_stream(&c->out, '[');
        do {
            if (!attached_only || context_find_from_pid(pe32.th32ProcessID) != NULL) {
                if (cnt > 0) write_stream(&c->out, ',');
                json_write_string(&c->out, pid2id(pe32.th32ProcessID, 0));
                cnt++;
            }
        }
        while (Process32Next(snapshot, &pe32));
        write_stream(&c->out, ']');
        write_stream(&c->out, 0);
    }
    if (snapshot != INVALID_HANDLE_VALUE) CloseHandle(snapshot);
#elif defined(_WRS_KERNEL)
        int i = 0;
        int cnt = 0;
        int ids_cnt = 0;
        int ids_max = 500;
        int * ids = (int *)loc_alloc(ids_max * sizeof(int));
        for (;;) {
            ids_cnt = taskIdListGet(ids, ids_max);
            if (ids_cnt < ids_max) break;
            loc_free(ids);
            ids_max *= 2;
            ids = (int *)loc_alloc(ids_max * sizeof(int));
        }
        write_errno(&c->out, 0);
        write_stream(&c->out, '[');
        for (i = 0; i < ids_cnt; i++) {
            if (!attached_only || context_find_from_pid(ids[i]) != NULL) {
                if (cnt > 0) write_stream(&c->out, ',');
                json_write_string(&c->out, pid2id(ids[i], 0));
                cnt++;
            }
        }
        write_stream(&c->out, ']');
        write_stream(&c->out, 0);
#elif defined(__APPLE__)
#else
        DIR * proc = opendir("/proc");
        if (proc == NULL) {
            write_errno(&c->out, errno);
            write_stringz(&c->out, "null");
        }
        else {
            int cnt = 0;
            write_errno(&c->out, 0);
            write_stream(&c->out, '[');
            for (;;) {
                struct dirent * ent = readdir(proc);
                if (ent == NULL) break;
                if (ent->d_name[0] >= '1' && ent->d_name[0] <= '9') {
                    pid_t pid = atol(ent->d_name);
                    if (!attached_only || context_find_from_pid(pid) != NULL) {
                        if (cnt > 0) write_stream(&c->out, ',');
                        json_write_string(&c->out, pid2id(pid, 0));
                        cnt++;
                    }
                }
            }
            write_stream(&c->out, ']');
            write_stream(&c->out, 0);
            closedir(proc);
        }
#endif
    }

    write_stream(&c->out, MARKER_EOM);
}