ds3.0/bin/
ds3.0/extra/
ds3.0/extra/crat/
ds3.0/extra/creremote/
ds3.0/extra/mingw/
ds3.0/extra/wolfpaw/
ds3.0/fluffos-2.18-ds07/
ds3.0/fluffos-2.18-ds07/Win32/
ds3.0/fluffos-2.18-ds07/compat/
ds3.0/fluffos-2.18-ds07/compat/simuls/
ds3.0/fluffos-2.18-ds07/testsuite/
ds3.0/fluffos-2.18-ds07/testsuite/clone/
ds3.0/fluffos-2.18-ds07/testsuite/command/
ds3.0/fluffos-2.18-ds07/testsuite/data/
ds3.0/fluffos-2.18-ds07/testsuite/etc/
ds3.0/fluffos-2.18-ds07/testsuite/include/
ds3.0/fluffos-2.18-ds07/testsuite/inherit/
ds3.0/fluffos-2.18-ds07/testsuite/inherit/master/
ds3.0/fluffos-2.18-ds07/testsuite/log/
ds3.0/fluffos-2.18-ds07/testsuite/single/
ds3.0/fluffos-2.18-ds07/testsuite/single/tests/compiler/
ds3.0/fluffos-2.18-ds07/testsuite/single/tests/efuns/
ds3.0/fluffos-2.18-ds07/testsuite/single/tests/operators/
ds3.0/fluffos-2.18-ds07/testsuite/u/
ds3.0/fluffos-2.18-ds07/tmp/
ds3.0/lib/cmds/admins/
ds3.0/lib/cmds/common/
ds3.0/lib/cmds/creators/include/
ds3.0/lib/daemon/services/
ds3.0/lib/daemon/tmp/
ds3.0/lib/doc/
ds3.0/lib/doc/bguide/
ds3.0/lib/doc/efun/all/
ds3.0/lib/doc/efun/arrays/
ds3.0/lib/doc/efun/buffers/
ds3.0/lib/doc/efun/compile/
ds3.0/lib/doc/efun/floats/
ds3.0/lib/doc/efun/functions/
ds3.0/lib/doc/efun/mixed/
ds3.0/lib/doc/efun/numbers/
ds3.0/lib/doc/efun/parsing/
ds3.0/lib/doc/help/classes/
ds3.0/lib/doc/help/races/
ds3.0/lib/doc/lfun/
ds3.0/lib/doc/lfun/all/
ds3.0/lib/doc/lfun/lib/abilities/
ds3.0/lib/doc/lfun/lib/armor/
ds3.0/lib/doc/lfun/lib/bank/
ds3.0/lib/doc/lfun/lib/bot/
ds3.0/lib/doc/lfun/lib/clay/
ds3.0/lib/doc/lfun/lib/clean/
ds3.0/lib/doc/lfun/lib/clerk/
ds3.0/lib/doc/lfun/lib/client/
ds3.0/lib/doc/lfun/lib/combat/
ds3.0/lib/doc/lfun/lib/connect/
ds3.0/lib/doc/lfun/lib/container/
ds3.0/lib/doc/lfun/lib/corpse/
ds3.0/lib/doc/lfun/lib/creator/
ds3.0/lib/doc/lfun/lib/daemon/
ds3.0/lib/doc/lfun/lib/damage/
ds3.0/lib/doc/lfun/lib/deterioration/
ds3.0/lib/doc/lfun/lib/donate/
ds3.0/lib/doc/lfun/lib/door/
ds3.0/lib/doc/lfun/lib/equip/
ds3.0/lib/doc/lfun/lib/file/
ds3.0/lib/doc/lfun/lib/fish/
ds3.0/lib/doc/lfun/lib/fishing/
ds3.0/lib/doc/lfun/lib/flashlight/
ds3.0/lib/doc/lfun/lib/follow/
ds3.0/lib/doc/lfun/lib/ftp_client/
ds3.0/lib/doc/lfun/lib/ftp_data_connection/
ds3.0/lib/doc/lfun/lib/fuel/
ds3.0/lib/doc/lfun/lib/furnace/
ds3.0/lib/doc/lfun/lib/genetics/
ds3.0/lib/doc/lfun/lib/holder/
ds3.0/lib/doc/lfun/lib/id/
ds3.0/lib/doc/lfun/lib/interactive/
ds3.0/lib/doc/lfun/lib/lamp/
ds3.0/lib/doc/lfun/lib/leader/
ds3.0/lib/doc/lfun/lib/light/
ds3.0/lib/doc/lfun/lib/limb/
ds3.0/lib/doc/lfun/lib/living/
ds3.0/lib/doc/lfun/lib/load/
ds3.0/lib/doc/lfun/lib/look/
ds3.0/lib/doc/lfun/lib/manipulate/
ds3.0/lib/doc/lfun/lib/meal/
ds3.0/lib/doc/lfun/lib/messages/
ds3.0/lib/doc/lfun/lib/player/
ds3.0/lib/doc/lfun/lib/poison/
ds3.0/lib/doc/lfun/lib/position/
ds3.0/lib/doc/lfun/lib/post_office/
ds3.0/lib/doc/lfun/lib/potion/
ds3.0/lib/doc/lfun/lib/room/
ds3.0/lib/doc/lfun/lib/server/
ds3.0/lib/doc/lfun/lib/spell/
ds3.0/lib/doc/lfun/lib/torch/
ds3.0/lib/doc/lfun/lib/vendor/
ds3.0/lib/doc/lfun/lib/virt_sky/
ds3.0/lib/doc/lfun/lib/weapon/
ds3.0/lib/doc/lfun/lib/worn_storage/
ds3.0/lib/doc/lpc/constructs/
ds3.0/lib/doc/lpc/etc/
ds3.0/lib/doc/lpc/intermediate/
ds3.0/lib/doc/lpc/types/
ds3.0/lib/doc/misc/
ds3.0/lib/doc/old/
ds3.0/lib/doc/phints/
ds3.0/lib/domains/
ds3.0/lib/domains/Praxis/adm/
ds3.0/lib/domains/Praxis/attic/
ds3.0/lib/domains/Praxis/cemetery/mon/
ds3.0/lib/domains/Praxis/data/
ds3.0/lib/domains/Praxis/death/
ds3.0/lib/domains/Praxis/mountains/
ds3.0/lib/domains/Praxis/obj/armour/
ds3.0/lib/domains/Praxis/obj/magic/
ds3.0/lib/domains/Praxis/obj/weapon/
ds3.0/lib/domains/Praxis/orc_valley/
ds3.0/lib/domains/Ylsrim/
ds3.0/lib/domains/Ylsrim/adm/
ds3.0/lib/domains/Ylsrim/armor/
ds3.0/lib/domains/Ylsrim/broken/
ds3.0/lib/domains/Ylsrim/fish/
ds3.0/lib/domains/Ylsrim/meal/
ds3.0/lib/domains/Ylsrim/npc/
ds3.0/lib/domains/Ylsrim/obj/
ds3.0/lib/domains/Ylsrim/virtual/
ds3.0/lib/domains/Ylsrim/weapon/
ds3.0/lib/domains/campus/adm/
ds3.0/lib/domains/campus/chamber/
ds3.0/lib/domains/campus/etc/
ds3.0/lib/domains/campus/meals/
ds3.0/lib/domains/campus/txt/ai/charles/
ds3.0/lib/domains/campus/txt/ai/charles/bak2/
ds3.0/lib/domains/campus/txt/ai/charles/bak2/bak1/
ds3.0/lib/domains/campus/txt/ai/charly/
ds3.0/lib/domains/campus/txt/ai/charly/bak/
ds3.0/lib/domains/campus/txt/jenny/
ds3.0/lib/domains/cave/doors/
ds3.0/lib/domains/cave/etc/
ds3.0/lib/domains/cave/meals/
ds3.0/lib/domains/cave/weap/
ds3.0/lib/domains/default/chamber/
ds3.0/lib/domains/default/creator/
ds3.0/lib/domains/default/doors/
ds3.0/lib/domains/default/etc/
ds3.0/lib/domains/default/vehicle/
ds3.0/lib/domains/default/virtual/
ds3.0/lib/domains/town/save/
ds3.0/lib/domains/town/txt/shame/
ds3.0/lib/domains/town/virtual/
ds3.0/lib/domains/town/virtual/bottom/
ds3.0/lib/domains/town/virtual/space/
ds3.0/lib/estates/
ds3.0/lib/ftp/
ds3.0/lib/lib/comp/
ds3.0/lib/lib/daemons/
ds3.0/lib/lib/daemons/include/
ds3.0/lib/lib/lvs/
ds3.0/lib/lib/user/
ds3.0/lib/lib/virtual/
ds3.0/lib/log/
ds3.0/lib/log/adm/
ds3.0/lib/log/archive/
ds3.0/lib/log/chan/
ds3.0/lib/log/errors/
ds3.0/lib/log/law/adm/
ds3.0/lib/log/law/email/
ds3.0/lib/log/law/names/
ds3.0/lib/log/law/sites-misc/
ds3.0/lib/log/law/sites-register/
ds3.0/lib/log/law/sites-tempban/
ds3.0/lib/log/law/sites-watch/
ds3.0/lib/log/open/
ds3.0/lib/log/reports/
ds3.0/lib/log/router/
ds3.0/lib/log/secure/
ds3.0/lib/log/watch/
ds3.0/lib/obj/book_source/
ds3.0/lib/obj/include/
ds3.0/lib/powers/prayers/
ds3.0/lib/powers/spells/
ds3.0/lib/realms/template/
ds3.0/lib/realms/template/adm/
ds3.0/lib/realms/template/area/
ds3.0/lib/realms/template/area/armor/
ds3.0/lib/realms/template/area/npc/
ds3.0/lib/realms/template/area/obj/
ds3.0/lib/realms/template/area/room/
ds3.0/lib/realms/template/area/weap/
ds3.0/lib/realms/template/bak/
ds3.0/lib/realms/template/cmds/
ds3.0/lib/save/kills/o/
ds3.0/lib/secure/cfg/classes/
ds3.0/lib/secure/cmds/builders/
ds3.0/lib/secure/cmds/creators/include/
ds3.0/lib/secure/cmds/players/
ds3.0/lib/secure/cmds/players/include/
ds3.0/lib/secure/daemon/imc2server/
ds3.0/lib/secure/daemon/include/
ds3.0/lib/secure/lib/
ds3.0/lib/secure/lib/include/
ds3.0/lib/secure/lib/net/include/
ds3.0/lib/secure/lib/std/
ds3.0/lib/secure/log/adm/
ds3.0/lib/secure/log/bak/
ds3.0/lib/secure/log/intermud/
ds3.0/lib/secure/log/network/
ds3.0/lib/secure/modules/
ds3.0/lib/secure/npc/
ds3.0/lib/secure/obj/include/
ds3.0/lib/secure/room/
ds3.0/lib/secure/save/
ds3.0/lib/secure/save/backup/
ds3.0/lib/secure/save/boards/
ds3.0/lib/secure/save/players/g/
ds3.0/lib/secure/tmp/
ds3.0/lib/secure/upgrades/files/
ds3.0/lib/secure/verbs/creators/
ds3.0/lib/std/board/
ds3.0/lib/std/lib/
ds3.0/lib/verbs/admins/include/
ds3.0/lib/verbs/builders/
ds3.0/lib/verbs/common/
ds3.0/lib/verbs/common/include/
ds3.0/lib/verbs/creators/
ds3.0/lib/verbs/creators/include/
ds3.0/lib/verbs/rooms/
ds3.0/lib/verbs/rooms/include/
ds3.0/lib/www/client/
ds3.0/lib/www/errors/
ds3.0/lib/www/images/
ds3.0/win32/
#include "std.h"
#include "../lpc_incl.h"
#include "async.h"
#include "../function.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#ifdef F_ASYNC_GETDIR
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <sys/syscall.h>
#endif
#include "../config.h"
#include "../interpret.h"
#include "../file.h"
#include "../function.h"
#include "../eval.h"
#ifdef F_ASYNC_DB_EXEC
#include "db.h"
#endif

enum atypes {
    aread,
    awrite,
    agetdir,
    adbexec,
    done
};

enum astates {
    BUSY,
    DONE,
};

struct request{
    char path[MAXPATHLEN];
    int flags;
    int status;
    int ret;
    const char *buf;
    int size;
    function_to_call_t *fun;
    struct request *next;
    svalue_t tmp;
    enum atypes type;
};

void add_req(struct request *req);

#if defined(F_ASYNC_READ) || defined(F_ASYNC_WRITE)

struct cb_mem{
    function_to_call_t cb;
    struct cb_mem *next;
} *cbs = 0;

struct req_mem{
    struct request req;
    struct req_mem *next;
} *reqms;

struct stuff{
    void *(*func)(struct request *);
    struct request *data;
    struct stuff *next;
} *todo, *lasttodo;

struct stuff_mem{
    struct stuff stuff;
    struct stuff_mem *next;
} *stuffs;

pthread_mutex_t mem_mut;


struct stuff *get_stuff(){
    struct stuff *ret;
    if(stuffs){
        pthread_mutex_lock(&mem_mut);
        ret = &stuffs->stuff;
        stuffs = stuffs->next;
        ((struct stuff_mem *)ret)->next = 0;
        pthread_mutex_unlock(&mem_mut);
    }else{
        ret = (struct stuff *)MALLOC(sizeof(struct stuff_mem));
        ((struct stuff_mem *)ret)->next = 0;
    }
    return ret;
}

void free_stuff(struct stuff *stuff){
    struct stuff_mem *stufft = (struct stuff_mem *)stuff;
    pthread_mutex_lock(&mem_mut);
    stufft->next = stuffs;
    stuffs = stufft;
    pthread_mutex_unlock(&mem_mut);
}

pthread_mutex_t mut;
pthread_mutex_t work_mut;
int thread_started = 0;

void *thread_func(void *mydata){
    while(1){
        pthread_mutex_lock(&mut);
        while(todo){
            pthread_mutex_lock(&work_mut);
            struct stuff *work = todo;
            todo = todo->next;
            if(!todo)
                lasttodo = NULL;
            pthread_mutex_unlock(&work_mut);
            work->func(work->data);
            free_stuff(work);
        }
    }
}

void do_stuff(void *(*func)(struct request *), struct request *data){
    if(!thread_started){
        pthread_mutex_init(&mut, NULL);
        pthread_mutex_init(&mem_mut, NULL);
        pthread_mutex_init(&work_mut, NULL);
        pthread_mutex_lock(&mut);
        pthread_t t;
        pthread_create(&t, NULL, &thread_func, NULL);
        thread_started = 1;
    }
    struct stuff *work = get_stuff();
    work->func = func;
    work->data = data;
    work->next = NULL;
    pthread_mutex_lock(&work_mut);
    add_req(data);
    if(lasttodo){
        lasttodo->next = work;
        lasttodo = work;
    } else {
        todo = lasttodo = work;
    }
    pthread_mutex_unlock(&work_mut);
    pthread_mutex_unlock(&mut);
}

function_to_call_t *get_cb(){
    function_to_call_t *ret;
    if(cbs){
        ret = &cbs->cb;
        cbs = cbs->next;
        ((struct cb_mem *)ret)->next = 0;
    }else{
        ret = (function_to_call_t *)MALLOC(sizeof(struct cb_mem));
        ((struct cb_mem *)ret)->next = 0;
    }
    memset(ret, 0, sizeof(function_to_call_t));
    return ret;
}

void free_cb(function_to_call_t *cb){
    struct cb_mem *cbt = (struct cb_mem *)cb;
    cbt->next = cbs;
    cbs = cbt;
}

struct request *get_req(){
    struct request *ret;
    if(reqms){
        ret = &reqms->req;
        reqms = reqms->next;
        ((struct req_mem *)ret)->next = 0;
    }else{
        ret = (struct request *)MALLOC(sizeof(struct req_mem));
        ((struct req_mem *)ret)->next = 0;
    }
    return ret;
}

void free_req(struct request *req){
    struct req_mem *reqt = (struct req_mem *)req;
    reqt->next = reqms;
    reqms = reqt;
}


static struct request *reqs = NULL;
static struct request *lastreq = NULL;
void add_req(struct request *req){
    if(lastreq){
        lastreq->next = req;
    } else {
        reqs = req;
    }
    req->next = NULL;
    lastreq = req;
}

#ifdef PACKAGE_COMPRESS
#include <zlib.h>

void *gzreadthread(struct request *req){
    void *file = gzopen(req->path, "rb");
    req->ret = gzread(file, (void *)(req->buf), req->size);
    req->status = DONE;
    gzclose(file);
    return NULL;
}

int aio_gzread(struct request *req){
    req->status = BUSY;
    do_stuff(gzreadthread, req);
    return 0;
}

void *gzwritethread(struct request *req){
    int fd = open(req->path, req->flags & 1 ? O_CREAT|O_WRONLY|O_TRUNC
            : O_CREAT|O_WRONLY|O_APPEND, S_IRWXU|S_IRWXG);
    void *file = gzdopen(fd, "wb");
    req->ret = gzwrite(file, (void *)(req->buf), req->size);
    req->status = DONE;
    gzclose(file);
    return NULL;
}

int aio_gzwrite(struct request *req){
    req->status = BUSY;
    do_stuff(gzwritethread, req);
    return 0;
}
#endif

void *writethread(struct request *req){
    int fd = open(req->path, req->flags & 1 ? O_CREAT|O_WRONLY|O_TRUNC
            : O_CREAT|O_WRONLY|O_APPEND, S_IRWXU|S_IRWXG);

    req->ret =  write(fd, req->buf, req->size);

    req->status = DONE;
    close(fd);
    return NULL;
}

int aio_write(struct request *req){
    req->status = BUSY;
    do_stuff(writethread, req);
    return 0;
}

void *readthread(struct request *req){
    int fd = open(req->path, O_RDONLY);
    req->ret = read(fd, (void *)(req->buf), req->size);
    req->status = DONE;
    close(fd);
    return NULL;
}

int aio_read(struct request *req){
    req->status = BUSY;
    do_stuff(readthread, req);
    return 0;
}

#ifdef F_ASYNC_DB_EXEC
pthread_mutex_t *db_mut = NULL;

void *dbexecthread(struct request *req){
    db_t *db = (db_t *)req->buf;
    int ret;
    if (db->type->execute) {
        pthread_mutex_lock(db_mut);
        ret = db->type->execute(&(db->c), req->tmp.u.string);
        if (ret == -1)
            if(db->type->error) {
                strncpy(req->path, db->type->error(&(db->c)), MAXPATHLEN-1);
            } else {
                strcpy(req->path, "Unknown error");
            }
        pthread_mutex_unlock(db_mut);
    }

    req->ret = ret;
    req->status = DONE;
    return NULL;
}

int aio_db_exec(struct request *req){
    req->status = BUSY;
    do_stuff(dbexecthread, req);
    return 0;
}
#endif

#ifdef F_ASYNC_GETDIR
void *getdirthread(struct request *req){
    int fd = open(req->path, O_RDONLY);
    int size = syscall(SYS_getdents, fd, req->buf, req->size);
    if(size == -1){
        close(fd);
        req->ret = 0;
        req->status = DONE;
        return NULL;
    }
    req->ret = size;
    while(size = syscall(SYS_getdents, fd, req->buf+req->ret, req->size-req->ret)){
        if(size == -1){
            close(fd);
            req->status = DONE;
            return NULL;
        }
        req->ret+=size;
    }
    req->status = DONE;
    close(fd);
    return NULL;
}

int aio_getdir(struct request *req){
    req->status = BUSY;
    do_stuff(getdirthread, req);
    return 0;
}

#endif

int add_read(const char *fname, function_to_call_t *fun) {
    if (fname) {
        struct request *req = get_req();
        //printf("fname: %s\n", fname);
        req->buf = (char *)MALLOC(READ_FILE_MAX_SIZE);
        req->size = READ_FILE_MAX_SIZE;
        req->fun = fun;
        req->type = aread;
        strcpy(req->path, fname);
#ifdef PACKAGE_COMPRESS
        return aio_gzread(req);
#else
        return aio_read(req);
#endif
    }else
        error("permission denied\n");
    return 1;
}

#ifdef F_ASYNC_GETDIR
extern int max_array_size;
int add_getdir(const char *fname, function_to_call_t *fun) {
    if (fname) {
        //printf("fname: %s\n", fname);
        struct request *req = get_req();
        req->buf = (char *)MALLOC(sizeof(struct dirent) * max_array_size);
        req->size = sizeof(struct dirent) * max_array_size;
        req->fun = fun;
        req->type = agetdir;
        strcpy(req->path, fname);
        return aio_getdir(req);
    }else
        error("permission denied\n");
    return 1;
}
#endif

int add_write(const char *fname, const char *buf, int size, char flags, function_to_call_t *fun) {
    if (fname) {
        struct request *req = get_req();
        req->buf = buf;
        req->size = size;
        req->fun = fun;
        req->type = awrite;
        req->flags = flags;
        strcpy(req->path, fname);
        assign_svalue_no_free(&req->tmp, sp-2);
#ifdef PACKAGE_COMPRESS
        if(flags & 2)
            return aio_gzwrite(req);
        else
#endif
            return aio_write(req);
    } else
        error("permission denied\n");
    return 1;
}

#ifdef F_ASYNC_DB_EXEC
int add_db_exec(db_t *db, function_to_call_t *fun) {
    struct request *req = get_req();
    req->fun = fun;
    req->type = adbexec;
    req->buf = (char *)db;
    assign_svalue_no_free(&req->tmp, sp-1);
    return aio_db_exec(req);
}
#endif


void handle_read(struct request *req){
    int val = req->ret;
    if(val < 0){
        FREE((void *)req->buf);
        push_number(val);
        set_eval(max_cost);
        safe_call_efun_callback(req->fun, 1);
        return;
    }
    char *file = new_string(val, "read_file_async: str");
    memcpy(file, (char *)(req->buf), val);
    file[val]=0;
    push_malloced_string(file);
    FREE((void *)req->buf);
    set_eval(max_cost);
    safe_call_efun_callback(req->fun, 1);
}

#ifdef F_ASYNC_GETDIR

struct linux_dirent {
    unsigned long  d_ino;     /* Inode number */
    unsigned long  d_off;     /* Offset to next dirent */
    unsigned short d_reclen;  /* Length of this dirent */
    char           d_name []; /* Filename (null-terminated) */
    /* length is actually (d_reclen - 2 -
       offsetof(struct linux_dirent, d_name) */
};


void handle_getdir(struct request *req){
    int val = req->ret;
    if(val>MAX_ARRAY_SIZE)
        val = MAX_ARRAY_SIZE;
    array_t *ret = allocate_empty_array(val);
    int i=0;
    if(val > 0)
    {
        struct linux_dirent *de = (struct linux_dirent *)req->buf;
        for(i=0; i<MAX_ARRAY_SIZE && ((char *)de) - (char *)(req->buf) < val; i++)
        {
            svalue_t *vp = &(ret->item[i]);
            vp->type = T_STRING;
            vp->subtype = STRING_MALLOC;
            vp->u.string = string_copy(de->d_name, "encode_stat");
            de = (struct linux_dirent *)(((char *)de) + de->d_reclen);
        }
    }
    ret = resize_array(ret, i);
    ret->size = i;
    push_refed_array(ret);
    FREE((void *)req->buf);
    set_eval(max_cost);
    safe_call_efun_callback(req->fun, 1);
}
#endif


void handle_write(struct request *req){
    free_svalue(&req->tmp, "handle_write");
    int val = req->ret;
    if(val < 0){
        push_number(val);
        set_eval(max_cost);
        safe_call_efun_callback(req->fun, 1);
        return;
    }
    push_undefined();
    set_eval(max_cost);
    safe_call_efun_callback(req->fun, 1);
}

void handle_db_exec(struct request *req){
    free_svalue(&req->tmp, "handle_db_exec");
    int val = req->ret;
    if(val == -1){
        copy_and_push_string(req->path);
    }
    else
        push_number(val);
    set_eval(max_cost);
    safe_call_efun_callback(req->fun, 1);
}

void check_reqs() {
    while (reqs) {
        int val = reqs->status;
        if (val != BUSY) {
            enum atypes type =  (reqs->type);
            reqs->type = done;
            switch (type) {
                case aread:
                    handle_read(reqs);
                    break;
                case awrite:
                    handle_write(reqs);
                    break;
#ifdef F_ASYNC_GETDIR
                case agetdir:
                    handle_getdir(reqs);
                    break;
#endif
#ifdef F_ASYNC_DB_EXEC
                case adbexec:
                    handle_db_exec(reqs);
                    break;
#endif
                case done:
                    //must have had an error while handling it before.
                    break;
                default:
                    fatal("unknown async type\n");
            }
            struct request *here = reqs;
            reqs = reqs->next;
            if(!reqs)
                lastreq = reqs;
            free_funp(here->fun->f.fp);
            free_cb(here->fun);
            free_req(here);
        } else
            return;
    }
}

    void complete_all_asyncio(){
        while(reqs)
            check_reqs();
    }

#ifdef F_ASYNC_READ

void f_async_read(){
    function_to_call_t *cb = get_cb();
    process_efun_callback(1, cb, F_ASYNC_READ);
    cb->f.fp->hdr.ref++;
    add_read(check_valid_path((sp-1)->u.string, current_object, "read_file", 0), cb);
    pop_2_elems();
}
#endif

#ifdef F_ASYNC_WRITE
void f_async_write(){
    function_to_call_t *cb = get_cb();
    process_efun_callback(3, cb, F_ASYNC_WRITE);
    cb->f.fp->hdr.ref++;
    add_write(check_valid_path((sp-3)->u.string, current_object, "write_file", 1), (sp-2)->u.string, strlen((sp-2)->u.string), (sp-1)->u.number, cb);
    pop_n_elems(4);
}
#endif

#ifdef F_ASYNC_GETDIR
void f_async_getdir(){
    function_to_call_t *cb = get_cb();
    process_efun_callback(1, cb, F_ASYNC_READ);
    cb->f.fp->hdr.ref++;
    add_getdir(check_valid_path((sp-1)->u.string, current_object, "get_dir", 0), cb);
    pop_2_elems();
}
#endif
#ifdef F_ASYNC_DB_EXEC
void f_async_db_exec(){
    array_t *info;
    db_t *db;
    info = allocate_empty_array(1);
    info->item[0].type = T_STRING;
    info->item[0].subtype = STRING_MALLOC;
    info->item[0].u.string = string_copy((sp-1)->u.string, "f_db_exec");
    int num_arg = st_num_arg;
    valid_database("exec", info);

    db = find_db_conn((sp-2)->u.number);
    if (!db) {
        error("Attempt to exec on an invalid database handle\n");
    }
    if(!db_mut){
        db_mut = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
        pthread_mutex_init(db_mut, NULL);
    }
    pthread_mutex_lock(db_mut);
    if (db->type->cleanup) {
        db->type->cleanup(&(db->c));
    }
    pthread_mutex_unlock(db_mut);
    st_num_arg = num_arg;
    function_to_call_t *cb = get_cb();
    process_efun_callback(2, cb, F_ASYNC_DB_EXEC);
    cb->f.fp->hdr.ref++;

    add_db_exec(db, cb);
    pop_2_elems();
}
#endif
#endif