wrote more code for process pipe device
This commit is contained in:
parent
b8b83d745c
commit
8b5a5bbc4f
@ -45,13 +45,13 @@ stio_LDFLAGS = $(LDFLAGS_LIB_COMMON)
|
|||||||
stio_LDADD = $(LIBADD_LIB_COMMON) -lstio
|
stio_LDADD = $(LIBADD_LIB_COMMON) -lstio
|
||||||
|
|
||||||
install-data-hook:
|
install-data-hook:
|
||||||
@echo "#ifndef _STIO_CFG_H_" > "$(DESTDIR)$(pkgincludedir)/stio-cfg.h"
|
@echo "#ifndef _STIO_CFG_H_" > "$(DESTDIR)$(includedir)/stio-cfg.h"
|
||||||
@echo "#define _STIO_CFG_H_" >> "$(DESTDIR)$(pkgincludedir)/stio-cfg.h"
|
@echo "#define _STIO_CFG_H_" >> "$(DESTDIR)$(includedir)/stio-cfg.h"
|
||||||
@$(EGREP) "#define[ ]+STIO_" "$(abs_builddir)/stio-cfg.h" >> "$(DESTDIR)$(pkgincludedir)/stio-cfg.h"
|
@$(EGREP) "#define[ ]+STIO_" "$(abs_builddir)/stio-cfg.h" >> "$(DESTDIR)$(includedir)/stio-cfg.h"
|
||||||
@echo "#endif" >> "$(DESTDIR)$(pkgincludedir)/stio-cfg.h"
|
@echo "#endif" >> "$(DESTDIR)$(includedir)/stio-cfg.h"
|
||||||
@$(RM) "$(DESTDIR)$(pkgincludedir)/stio-cfg.h.in"
|
@$(RM) "$(DESTDIR)$(includedir)/stio-cfg.h.in"
|
||||||
@$(SED) 's|/\*#define STIO_HAVE_CFG_H\*/|#define STIO_HAVE_CFG_H|' "$(srcdir)/stio-cmn.h" > "$(DESTDIR)$(pkgincludedir)/stio-cmn.h"
|
@$(SED) 's|/\*#define STIO_HAVE_CFG_H\*/|#define STIO_HAVE_CFG_H|' "$(srcdir)/stio-cmn.h" > "$(DESTDIR)$(includedir)/stio-cmn.h"
|
||||||
|
|
||||||
uninstall-hook:
|
uninstall-hook:
|
||||||
@$(RM) "$(DESTDIR)$(pkgincludedir)/stio-cfg.h"
|
@$(RM) "$(DESTDIR)$(includedir)/stio-cfg.h"
|
||||||
|
|
||||||
|
@ -807,15 +807,15 @@ uninstall-am: uninstall-binPROGRAMS uninstall-includeHEADERS \
|
|||||||
|
|
||||||
|
|
||||||
install-data-hook:
|
install-data-hook:
|
||||||
@echo "#ifndef _STIO_CFG_H_" > "$(DESTDIR)$(pkgincludedir)/stio-cfg.h"
|
@echo "#ifndef _STIO_CFG_H_" > "$(DESTDIR)$(includedir)/stio-cfg.h"
|
||||||
@echo "#define _STIO_CFG_H_" >> "$(DESTDIR)$(pkgincludedir)/stio-cfg.h"
|
@echo "#define _STIO_CFG_H_" >> "$(DESTDIR)$(includedir)/stio-cfg.h"
|
||||||
@$(EGREP) "#define[ ]+STIO_" "$(abs_builddir)/stio-cfg.h" >> "$(DESTDIR)$(pkgincludedir)/stio-cfg.h"
|
@$(EGREP) "#define[ ]+STIO_" "$(abs_builddir)/stio-cfg.h" >> "$(DESTDIR)$(includedir)/stio-cfg.h"
|
||||||
@echo "#endif" >> "$(DESTDIR)$(pkgincludedir)/stio-cfg.h"
|
@echo "#endif" >> "$(DESTDIR)$(includedir)/stio-cfg.h"
|
||||||
@$(RM) "$(DESTDIR)$(pkgincludedir)/stio-cfg.h.in"
|
@$(RM) "$(DESTDIR)$(includedir)/stio-cfg.h.in"
|
||||||
@$(SED) 's|/\*#define STIO_HAVE_CFG_H\*/|#define STIO_HAVE_CFG_H|' "$(srcdir)/stio-cmn.h" > "$(DESTDIR)$(pkgincludedir)/stio-cmn.h"
|
@$(SED) 's|/\*#define STIO_HAVE_CFG_H\*/|#define STIO_HAVE_CFG_H|' "$(srcdir)/stio-cmn.h" > "$(DESTDIR)$(includedir)/stio-cmn.h"
|
||||||
|
|
||||||
uninstall-hook:
|
uninstall-hook:
|
||||||
@$(RM) "$(DESTDIR)$(pkgincludedir)/stio-cfg.h"
|
@$(RM) "$(DESTDIR)$(includedir)/stio-cfg.h"
|
||||||
|
|
||||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||||
|
@ -214,9 +214,14 @@ static int arp_sck_on_write (stio_dev_sck_t* dev, stio_iolen_t wrlen, void* wrct
|
|||||||
|
|
||||||
/* ========================================================================= */
|
/* ========================================================================= */
|
||||||
|
|
||||||
static int pro_on_read (stio_dev_pro_t* dev, const void* data, stio_iolen_t dlen)
|
static void pro_on_close (stio_dev_pro_t* dev, stio_dev_pro_sid_t sid)
|
||||||
{
|
{
|
||||||
printf ("PROCESS READ DATA... [%.*s]\n", (int)dlen, (char*)data);
|
printf (">>>>>>>>>>>>> ON CLOSE OF SLAVE %d.\n", sid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pro_on_read (stio_dev_pro_t* dev, const void* data, stio_iolen_t dlen, stio_dev_pro_sid_t sid)
|
||||||
|
{
|
||||||
|
printf ("PROCESS READ DATA on SLAVE[%d]... [%.*s]\n", (int)sid, (int)dlen, (char*)data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,6 +275,12 @@ int main ()
|
|||||||
sigact.sa_handler = SIG_IGN;
|
sigact.sa_handler = SIG_IGN;
|
||||||
sigaction (SIGPIPE, &sigact, STIO_NULL);
|
sigaction (SIGPIPE, &sigact, STIO_NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
memset (&sigact, 0, STIO_SIZEOF(sigact));
|
||||||
|
sigact.sa_handler = SIG_IGN;
|
||||||
|
sigaction (SIGCHLD, &sigact, STIO_NULL);
|
||||||
|
*/
|
||||||
|
|
||||||
/*memset (&sin, 0, STIO_SIZEOF(sin));
|
/*memset (&sin, 0, STIO_SIZEOF(sin));
|
||||||
sin.sin_family = AF_INET;
|
sin.sin_family = AF_INET;
|
||||||
sin.sin_port = htons(1234); */
|
sin.sin_port = htons(1234); */
|
||||||
@ -394,11 +405,13 @@ int main ()
|
|||||||
stio_dev_pro_make_t pro_make;
|
stio_dev_pro_make_t pro_make;
|
||||||
|
|
||||||
memset (&pro_make, 0, STIO_SIZEOF(pro_make));
|
memset (&pro_make, 0, STIO_SIZEOF(pro_make));
|
||||||
pro_make.flags = STIO_DEV_PRO_READOUT | STIO_DEV_PRO_READERR | STIO_DEV_PRO_WRITEIN;
|
pro_make.flags = STIO_DEV_PRO_READOUT | STIO_DEV_PRO_READERR | STIO_DEV_PRO_WRITEIN /*| STIO_DEV_PRO_FORGET_CHILD*/;
|
||||||
//pro_make.cmd = "/bin/ls -laF /usr/bin";
|
//pro_make.cmd = "/bin/ls -laF /usr/bin";
|
||||||
pro_make.cmd = "/bin/ls -laF";
|
//pro_make.cmd = "/bin/ls -laF";
|
||||||
|
pro_make.cmd = "./a";
|
||||||
pro_make.on_read = pro_on_read;
|
pro_make.on_read = pro_on_read;
|
||||||
pro_make.on_write = pro_on_write;
|
pro_make.on_write = pro_on_write;
|
||||||
|
pro_make.on_close = pro_on_close;
|
||||||
|
|
||||||
pro = stio_dev_pro_make (stio, 0, &pro_make);
|
pro = stio_dev_pro_make (stio, 0, &pro_make);
|
||||||
if (!pro)
|
if (!pro)
|
||||||
@ -406,6 +419,11 @@ int main ()
|
|||||||
printf ("CANNOT CREATE PROCESS PIPE\n");
|
printf ("CANNOT CREATE PROCESS PIPE\n");
|
||||||
goto oops;
|
goto oops;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stio_dev_pro_write (pro, "MY STIO LIBRARY\n", 16, STIO_NULL);
|
||||||
|
//stio_dev_pro_close (pro, STIO_DEV_PRO_IN);
|
||||||
|
//stio_dev_pro_close (pro, STIO_DEV_PRO_OUT);
|
||||||
|
//stio_dev_pro_close (pro, STIO_DEV_PRO_ERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
stio_loop (stio);
|
stio_loop (stio);
|
||||||
|
@ -39,7 +39,7 @@ struct slave_info_t
|
|||||||
stio_dev_pro_make_t* mi;
|
stio_dev_pro_make_t* mi;
|
||||||
stio_syshnd_t pfd;
|
stio_syshnd_t pfd;
|
||||||
int dev_capa;
|
int dev_capa;
|
||||||
int id;
|
stio_dev_pro_sid_t id;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct slave_info_t slave_info_t;
|
typedef struct slave_info_t slave_info_t;
|
||||||
@ -221,7 +221,7 @@ static pid_t standard_fork_and_exec (stio_t* stio, int pfds[], int flags, param_
|
|||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_pro_make (stio_dev_t* dev, void* ctx)
|
static int dev_pro_make_master (stio_dev_t* dev, void* ctx)
|
||||||
{
|
{
|
||||||
stio_dev_pro_t* rdev = (stio_dev_pro_t*)dev;
|
stio_dev_pro_t* rdev = (stio_dev_pro_t*)dev;
|
||||||
stio_dev_pro_make_t* info = (stio_dev_pro_make_t*)ctx;
|
stio_dev_pro_make_t* info = (stio_dev_pro_make_t*)ctx;
|
||||||
@ -332,12 +332,13 @@ static int dev_pro_make (stio_dev_t* dev, void* ctx)
|
|||||||
si.mi = info;
|
si.mi = info;
|
||||||
si.pfd = pfds[1];
|
si.pfd = pfds[1];
|
||||||
si.dev_capa = STIO_DEV_CAPA_OUT | STIO_DEV_CAPA_OUT_QUEUED | STIO_DEV_CAPA_STREAM;
|
si.dev_capa = STIO_DEV_CAPA_OUT | STIO_DEV_CAPA_OUT_QUEUED | STIO_DEV_CAPA_STREAM;
|
||||||
si.id = 0;
|
si.id = STIO_DEV_PRO_IN;
|
||||||
|
|
||||||
rdev->slave[0] = make_slave (dev->stio, &si);
|
rdev->slave[STIO_DEV_PRO_IN] = make_slave (dev->stio, &si);
|
||||||
if (!rdev->slave[0]) goto oops;
|
if (!rdev->slave[STIO_DEV_PRO_IN]) goto oops;
|
||||||
|
|
||||||
pfds[1] = STIO_SYSHND_INVALID;
|
pfds[1] = STIO_SYSHND_INVALID;
|
||||||
|
rdev->slave_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pfds[2] != STIO_SYSHND_INVALID)
|
if (pfds[2] != STIO_SYSHND_INVALID)
|
||||||
@ -348,12 +349,13 @@ static int dev_pro_make (stio_dev_t* dev, void* ctx)
|
|||||||
si.mi = info;
|
si.mi = info;
|
||||||
si.pfd = pfds[2];
|
si.pfd = pfds[2];
|
||||||
si.dev_capa = STIO_DEV_CAPA_IN | STIO_DEV_CAPA_STREAM;
|
si.dev_capa = STIO_DEV_CAPA_IN | STIO_DEV_CAPA_STREAM;
|
||||||
si.id = 1;
|
si.id = STIO_DEV_PRO_OUT;
|
||||||
|
|
||||||
rdev->slave[1] = make_slave (dev->stio, &si);
|
rdev->slave[STIO_DEV_PRO_OUT] = make_slave (dev->stio, &si);
|
||||||
if (!rdev->slave[1]) goto oops;
|
if (!rdev->slave[STIO_DEV_PRO_OUT]) goto oops;
|
||||||
|
|
||||||
pfds[2] = STIO_SYSHND_INVALID;
|
pfds[2] = STIO_SYSHND_INVALID;
|
||||||
|
rdev->slave_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pfds[4] != STIO_SYSHND_INVALID)
|
if (pfds[4] != STIO_SYSHND_INVALID)
|
||||||
@ -364,22 +366,25 @@ static int dev_pro_make (stio_dev_t* dev, void* ctx)
|
|||||||
si.mi = info;
|
si.mi = info;
|
||||||
si.pfd = pfds[4];
|
si.pfd = pfds[4];
|
||||||
si.dev_capa = STIO_DEV_CAPA_IN | STIO_DEV_CAPA_STREAM;
|
si.dev_capa = STIO_DEV_CAPA_IN | STIO_DEV_CAPA_STREAM;
|
||||||
si.id = 2;
|
si.id = STIO_DEV_PRO_ERR;
|
||||||
|
|
||||||
rdev->slave[2] = make_slave (dev->stio, &si);
|
rdev->slave[STIO_DEV_PRO_ERR] = make_slave (dev->stio, &si);
|
||||||
if (!rdev->slave[2]) goto oops;
|
if (!rdev->slave[STIO_DEV_PRO_ERR]) goto oops;
|
||||||
|
|
||||||
pfds[4] = STIO_SYSHND_INVALID;
|
pfds[4] = STIO_SYSHND_INVALID;
|
||||||
|
rdev->slave_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < 3; i++)
|
for (i = 0; i < STIO_COUNTOF(rdev->slave); i++)
|
||||||
{
|
{
|
||||||
if (rdev->slave[i]) rdev->slave[i]->master = rdev;
|
if (rdev->slave[i]) rdev->slave[i]->master = rdev;
|
||||||
}
|
}
|
||||||
|
|
||||||
rdev->dev_capa = STIO_DEV_CAPA_VIRTUAL;
|
rdev->dev_capa = STIO_DEV_CAPA_VIRTUAL; /* the master device doesn't perform I/O */
|
||||||
|
rdev->flags = info->flags;
|
||||||
rdev->on_read = info->on_read;
|
rdev->on_read = info->on_read;
|
||||||
rdev->on_write = info->on_write;
|
rdev->on_write = info->on_write;
|
||||||
|
rdev->on_close = info->on_close;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
oops:
|
oops:
|
||||||
@ -394,7 +399,7 @@ oops:
|
|||||||
free_param (rdev->stio, ¶m);
|
free_param (rdev->stio, ¶m);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 3; i > 0; )
|
for (i = STIO_COUNTOF(rdev->slave); i > 0; )
|
||||||
{
|
{
|
||||||
i--;
|
i--;
|
||||||
if (rdev->slave[i])
|
if (rdev->slave[i])
|
||||||
@ -403,6 +408,7 @@ oops:
|
|||||||
rdev->slave[i] = STIO_NULL;
|
rdev->slave[i] = STIO_NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
rdev->slave_count = 0;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -421,57 +427,117 @@ static int dev_pro_make_slave (stio_dev_t* dev, void* ctx)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_pro_kill (stio_dev_t* dev)
|
static int dev_pro_kill_master (stio_dev_t* dev, int force)
|
||||||
{
|
{
|
||||||
stio_dev_pro_t* rdev = (stio_dev_pro_t*)dev;
|
stio_dev_pro_t* rdev = (stio_dev_pro_t*)dev;
|
||||||
int i, status;
|
int i, status;
|
||||||
|
pid_t wpid;
|
||||||
|
|
||||||
for (i = 0; i < 3; i++)
|
if (rdev->slave_count > 0)
|
||||||
{
|
{
|
||||||
if (rdev->slave[i])
|
for (i = 0; i < STIO_COUNTOF(rdev->slave); i++)
|
||||||
{
|
{
|
||||||
stio_dev_pro_slave_t* sdev = rdev->slave[i];
|
if (rdev->slave[i])
|
||||||
rdev->slave[i] = STIO_NULL;
|
{
|
||||||
stio_killdev (rdev->stio, (stio_dev_t*)sdev);
|
stio_dev_pro_slave_t* sdev = rdev->slave[i];
|
||||||
|
|
||||||
|
/* nullify the pointer to the slave device
|
||||||
|
* before calling stio_killdev() on the slave device.
|
||||||
|
* the slave device can check this pointer to tell from
|
||||||
|
* self-initiated termination or master-driven termination */
|
||||||
|
rdev->slave[i] = STIO_NULL;
|
||||||
|
|
||||||
|
stio_killdev (rdev->stio, (stio_dev_t*)sdev);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
if (rdev->child_pid >= 0)
|
||||||
x = waitpid (rdev->child_pid, &status, WNOHANG);
|
|
||||||
if (x == rdev->child_pid)
|
|
||||||
{
|
{
|
||||||
/* child process reclaimed successfully */
|
if (!(rdev->flags & STIO_DEV_PRO_FORGET_CHILD))
|
||||||
|
{
|
||||||
|
int killed = 0;
|
||||||
|
|
||||||
|
await_child:
|
||||||
|
wpid = waitpid (rdev->child_pid, &status, WNOHANG);
|
||||||
|
if (wpid == 0)
|
||||||
|
{
|
||||||
|
if (force && !killed)
|
||||||
|
{
|
||||||
|
if (!(rdev->flags & STIO_DEV_PRO_FORGET_DIEHARD_CHILD))
|
||||||
|
{
|
||||||
|
kill (rdev->child_pid, SIGKILL);
|
||||||
|
killed = 1;
|
||||||
|
goto await_child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* child process is still alive */
|
||||||
|
rdev->stio->errnum = STIO_EAGAIN;
|
||||||
|
return -1; /* call me again */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wpid == rdev->child_pid => full success
|
||||||
|
* wpid == -1 && errno == ECHILD => no such process. it's waitpid()'ed by some other part of the program?
|
||||||
|
* other cases ==> can't really handle properly. forget it by returning success
|
||||||
|
* no need not worry about EINTR because errno can't have the value when WNOHANG is set.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
printf (">>>>>>>>>>>>>>>>>>> REAPED CHILD %d\n", (int)rdev->child_pid);
|
||||||
|
rdev->child_pid = -1;
|
||||||
}
|
}
|
||||||
else if (x == 0)
|
|
||||||
{
|
if (rdev->on_close) rdev->on_close (rdev, STIO_DEV_PRO_MASTER);
|
||||||
/* child still alive */
|
return 0;
|
||||||
/* TODO: schedule a timer job... */
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
kill (rdev->child_pid, SIGKILL);
|
|
||||||
x = waitpid (rdev->child_pid, &i, WNOHANG);
|
|
||||||
if (x == -1)
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_pro_kill_slave (stio_dev_t* dev)
|
static int dev_pro_kill_slave (stio_dev_t* dev, int force)
|
||||||
{
|
{
|
||||||
stio_dev_pro_slave_t* rdev = (stio_dev_pro_slave_t*)dev;
|
stio_dev_pro_slave_t* rdev = (stio_dev_pro_slave_t*)dev;
|
||||||
|
|
||||||
|
if (rdev->master)
|
||||||
|
{
|
||||||
|
stio_dev_pro_t* master;
|
||||||
|
|
||||||
|
master = rdev->master;
|
||||||
|
rdev->master = STIO_NULL;
|
||||||
|
|
||||||
|
/* indicate EOF */
|
||||||
|
if (master->on_close) master->on_close (master, rdev->id);
|
||||||
|
|
||||||
|
STIO_ASSERT (master->slave_count > 0);
|
||||||
|
master->slave_count--;
|
||||||
|
|
||||||
|
if (master->slave[rdev->id])
|
||||||
|
{
|
||||||
|
/* this call is started by the slave device itself.
|
||||||
|
* if this is the last slave, kill the master also */
|
||||||
|
if (master->slave_count <= 0)
|
||||||
|
{
|
||||||
|
stio_killdev (rdev->stio, (stio_dev_t*)master);
|
||||||
|
/* the master pointer is not valid from this point onwards
|
||||||
|
* as the actual master device object is freed in stio_killdev() */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* this call is initiated by this slave device itself.
|
||||||
|
* if it were by the master device, it would be STIO_NULL as
|
||||||
|
* nullified by the dev_pro_kill() */
|
||||||
|
master->slave[rdev->id] = STIO_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (rdev->pfd != STIO_SYSHND_INVALID)
|
if (rdev->pfd != STIO_SYSHND_INVALID)
|
||||||
{
|
{
|
||||||
close (rdev->pfd);
|
close (rdev->pfd);
|
||||||
rdev->pfd = STIO_SYSHND_INVALID;
|
rdev->pfd = STIO_SYSHND_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rdev->master)
|
return 0;
|
||||||
{
|
|
||||||
/* let the master know that this slave device has been killed */
|
|
||||||
rdev->master->slave[rdev->id] = STIO_NULL;
|
|
||||||
rdev->master = STIO_NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_pro_read_slave (stio_dev_t* dev, void* buf, stio_iolen_t* len, stio_devadr_t* srcadr)
|
static int dev_pro_read_slave (stio_dev_t* dev, void* buf, stio_iolen_t* len, stio_devadr_t* srcadr)
|
||||||
@ -523,25 +589,38 @@ static stio_syshnd_t dev_pro_getsyshnd_slave (stio_dev_t* dev)
|
|||||||
|
|
||||||
static int dev_pro_ioctl (stio_dev_t* dev, int cmd, void* arg)
|
static int dev_pro_ioctl (stio_dev_t* dev, int cmd, void* arg)
|
||||||
{
|
{
|
||||||
|
stio_dev_pro_t* rdev = (stio_dev_pro_t*)dev;
|
||||||
|
|
||||||
/*
|
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
case STIO_DEV_PRO_KILL
|
case STIO_DEV_PRO_CLOSE:
|
||||||
case STIO_DEV_PRO_CLOSEIN:
|
{
|
||||||
case STIO_DEV_PRO_CLOSEOUT:
|
stio_dev_pro_sid_t sid = *(stio_dev_pro_sid_t*)arg;
|
||||||
case STIO_DEV_PRO_CLOSEERR:
|
|
||||||
case STIO_DEV_PRO_WAIT:
|
if (sid < STIO_DEV_PRO_IN || sid > STIO_DEV_PRO_ERR)
|
||||||
|
{
|
||||||
|
rdev->stio->errnum = STIO_EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rdev->slave[sid])
|
||||||
|
{
|
||||||
|
/* unlike dev_pro_kill_master(), i don't nullify rdev->slave[sid].
|
||||||
|
* so i treat the closing ioctl as if it's a kill request
|
||||||
|
* initiated by the slave device itself. */
|
||||||
|
stio_killdev (rdev->stio, (stio_dev_t*)rdev->slave[sid]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static stio_dev_mth_t dev_pro_methods =
|
static stio_dev_mth_t dev_pro_methods =
|
||||||
{
|
{
|
||||||
dev_pro_make,
|
dev_pro_make_master,
|
||||||
dev_pro_kill,
|
dev_pro_kill_master,
|
||||||
dev_pro_getsyshnd,
|
dev_pro_getsyshnd,
|
||||||
|
|
||||||
STIO_NULL,
|
STIO_NULL,
|
||||||
@ -617,10 +696,17 @@ static int pro_ready_slave (stio_dev_t* dev, int events)
|
|||||||
return 1; /* the device is ok. carry on reading or writing */
|
return 1; /* the device is ok. carry on reading or writing */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pro_on_read_slave (stio_dev_t* dev, const void* data, stio_iolen_t len, const stio_devadr_t* srcadr)
|
|
||||||
|
static int pro_on_read_slave_out (stio_dev_t* dev, const void* data, stio_iolen_t len, const stio_devadr_t* srcadr)
|
||||||
{
|
{
|
||||||
stio_dev_pro_slave_t* pro = (stio_dev_pro_slave_t*)dev;
|
stio_dev_pro_slave_t* pro = (stio_dev_pro_slave_t*)dev;
|
||||||
return pro->master->on_read (pro->master, data, len);
|
return pro->master->on_read (pro->master, data, len, STIO_DEV_PRO_OUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pro_on_read_slave_err (stio_dev_t* dev, const void* data, stio_iolen_t len, const stio_devadr_t* srcadr)
|
||||||
|
{
|
||||||
|
stio_dev_pro_slave_t* pro = (stio_dev_pro_slave_t*)dev;
|
||||||
|
return pro->master->on_read (pro->master, data, len, STIO_DEV_PRO_ERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pro_on_write_slave (stio_dev_t* dev, stio_iolen_t wrlen, void* wrctx, const stio_devadr_t* dstadr)
|
static int pro_on_write_slave (stio_dev_t* dev, stio_iolen_t wrlen, void* wrctx, const stio_devadr_t* dstadr)
|
||||||
@ -629,21 +715,52 @@ static int pro_on_write_slave (stio_dev_t* dev, stio_iolen_t wrlen, void* wrctx,
|
|||||||
return pro->master->on_write (pro->master, wrlen, wrctx);
|
return pro->master->on_write (pro->master, wrlen, wrctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static stio_dev_evcb_t dev_pro_event_callbacks_slave =
|
static stio_dev_evcb_t dev_pro_event_callbacks_slave_in =
|
||||||
{
|
{
|
||||||
pro_ready_slave,
|
pro_ready_slave,
|
||||||
pro_on_read_slave,
|
STIO_NULL,
|
||||||
pro_on_write_slave
|
pro_on_write_slave
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static stio_dev_evcb_t dev_pro_event_callbacks_slave_out =
|
||||||
|
{
|
||||||
|
pro_ready_slave,
|
||||||
|
pro_on_read_slave_out,
|
||||||
|
STIO_NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static stio_dev_evcb_t dev_pro_event_callbacks_slave_err =
|
||||||
|
{
|
||||||
|
pro_ready_slave,
|
||||||
|
pro_on_read_slave_err,
|
||||||
|
STIO_NULL
|
||||||
|
};
|
||||||
|
|
||||||
/* ========================================================================= */
|
/* ========================================================================= */
|
||||||
|
|
||||||
static stio_dev_pro_slave_t* make_slave (stio_t* stio, slave_info_t* si)
|
static stio_dev_pro_slave_t* make_slave (stio_t* stio, slave_info_t* si)
|
||||||
{
|
{
|
||||||
return (stio_dev_pro_slave_t*)stio_makedev (
|
switch (si->id)
|
||||||
stio, STIO_SIZEOF(stio_dev_pro_t),
|
{
|
||||||
&dev_pro_methods_slave, &dev_pro_event_callbacks_slave, si);
|
case STIO_DEV_PRO_IN:
|
||||||
|
return (stio_dev_pro_slave_t*)stio_makedev (
|
||||||
|
stio, STIO_SIZEOF(stio_dev_pro_t),
|
||||||
|
&dev_pro_methods_slave, &dev_pro_event_callbacks_slave_in, si);
|
||||||
|
|
||||||
|
case STIO_DEV_PRO_OUT:
|
||||||
|
return (stio_dev_pro_slave_t*)stio_makedev (
|
||||||
|
stio, STIO_SIZEOF(stio_dev_pro_t),
|
||||||
|
&dev_pro_methods_slave, &dev_pro_event_callbacks_slave_out, si);
|
||||||
|
|
||||||
|
case STIO_DEV_PRO_ERR:
|
||||||
|
return (stio_dev_pro_slave_t*)stio_makedev (
|
||||||
|
stio, STIO_SIZEOF(stio_dev_pro_t),
|
||||||
|
&dev_pro_methods_slave, &dev_pro_event_callbacks_slave_err, si);
|
||||||
|
|
||||||
|
default:
|
||||||
|
stio->errnum = STIO_EINVAL;
|
||||||
|
return STIO_NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stio_dev_pro_t* stio_dev_pro_make (stio_t* stio, stio_size_t xtnsize, const stio_dev_pro_make_t* info)
|
stio_dev_pro_t* stio_dev_pro_make (stio_t* stio, stio_size_t xtnsize, const stio_dev_pro_make_t* info)
|
||||||
@ -684,8 +801,14 @@ int stio_dev_pro_timedwrite (stio_dev_pro_t* dev, const void* data, stio_iolen_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int stio_dev_pro_close (stio_dev_pro_t* dev, stio_dev_pro_sid_t sid)
|
||||||
|
{
|
||||||
|
return stio_dev_ioctl ((stio_dev_t*)dev, STIO_DEV_PRO_CLOSE, &sid);
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
stio_dev_pro_t* stio_dev_pro_getdev (stio_dev_pro_t* pro, stio_dev_pro_type_t type)
|
stio_dev_pro_t* stio_dev_pro_getdev (stio_dev_pro_t* pro, stio_dev_pro_sid_t sid)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
@ -29,42 +29,44 @@
|
|||||||
|
|
||||||
#include <stio.h>
|
#include <stio.h>
|
||||||
|
|
||||||
enum stio_dev_pro_type_t
|
enum stio_dev_pro_sid_t
|
||||||
{
|
{
|
||||||
STIO_DEV_PRO_IN,
|
STIO_DEV_PRO_MASTER = -1,
|
||||||
STIO_DEV_PRO_OUT,
|
STIO_DEV_PRO_IN = 0,
|
||||||
STIO_DEV_PRO_ERR,
|
STIO_DEV_PRO_OUT = 1,
|
||||||
|
STIO_DEV_PRO_ERR = 2
|
||||||
};
|
};
|
||||||
typedef enum stio_dev_pro_type_t stio_dev_pro_type_t;
|
typedef enum stio_dev_pro_sid_t stio_dev_pro_sid_t;
|
||||||
|
|
||||||
typedef struct stio_dev_pro_t stio_dev_pro_t;
|
typedef struct stio_dev_pro_t stio_dev_pro_t;
|
||||||
typedef struct stio_dev_pro_slave_t stio_dev_pro_slave_t;
|
typedef struct stio_dev_pro_slave_t stio_dev_pro_slave_t;
|
||||||
|
|
||||||
typedef int (*stio_dev_pro_on_read_t) (stio_dev_pro_t* dev, const void* data, stio_iolen_t len);
|
typedef int (*stio_dev_pro_on_read_t) (stio_dev_pro_t* dev, const void* data, stio_iolen_t len, stio_dev_pro_sid_t sid);
|
||||||
typedef int (*stio_dev_pro_on_write_t) (stio_dev_pro_t* dev, stio_iolen_t wrlen, void* wrctx);
|
typedef int (*stio_dev_pro_on_write_t) (stio_dev_pro_t* dev, stio_iolen_t wrlen, void* wrctx);
|
||||||
|
typedef void (*stio_dev_pro_on_close_t) (stio_dev_pro_t* dev, stio_dev_pro_sid_t sid);
|
||||||
|
|
||||||
struct stio_dev_pro_t
|
struct stio_dev_pro_t
|
||||||
{
|
{
|
||||||
STIO_DEV_HEADERS;
|
STIO_DEV_HEADERS;
|
||||||
|
|
||||||
stio_dev_pro_type_t type;
|
int flags;
|
||||||
|
|
||||||
stio_intptr_t child_pid;
|
stio_intptr_t child_pid;
|
||||||
stio_dev_pro_slave_t* slave[3];
|
stio_dev_pro_slave_t* slave[3];
|
||||||
|
int slave_count;
|
||||||
|
|
||||||
stio_dev_pro_on_read_t on_read;
|
stio_dev_pro_on_read_t on_read;
|
||||||
stio_dev_pro_on_write_t on_write;
|
stio_dev_pro_on_write_t on_write;
|
||||||
|
stio_dev_pro_on_close_t on_close;
|
||||||
|
|
||||||
stio_tmridx_t tmridx_connect;
|
stio_tmridx_t tmridx_connect;
|
||||||
|
|
||||||
stio_mchar_t* mcmd;
|
stio_mchar_t* mcmd;
|
||||||
int flags;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct stio_dev_pro_slave_t
|
struct stio_dev_pro_slave_t
|
||||||
{
|
{
|
||||||
STIO_DEV_HEADERS;
|
STIO_DEV_HEADERS;
|
||||||
int id;
|
stio_dev_pro_sid_t id;
|
||||||
stio_syshnd_t pfd;
|
stio_syshnd_t pfd;
|
||||||
stio_dev_pro_t* master; /* parent device */
|
stio_dev_pro_t* master; /* parent device */
|
||||||
};
|
};
|
||||||
@ -87,7 +89,16 @@ enum stio_dev_pro_make_flag_t
|
|||||||
STUO_DEV_PRO_DROPERR = (1 << 10),
|
STUO_DEV_PRO_DROPERR = (1 << 10),
|
||||||
|
|
||||||
|
|
||||||
STIO_DEV_PRO_SHELL = (1 << 13),
|
STIO_DEV_PRO_SHELL = (1 << 13),
|
||||||
|
|
||||||
|
/* perform no waitpid() on a child process upon device destruction.
|
||||||
|
* you should set this flag if your application has automatic child
|
||||||
|
* process reaping enabled. for instance, SIGCHLD is set to SIG_IGN
|
||||||
|
* on POSIX.1-2001 compliant systems */
|
||||||
|
STIO_DEV_PRO_FORGET_CHILD = (1 << 14),
|
||||||
|
|
||||||
|
|
||||||
|
STIO_DEV_PRO_FORGET_DIEHARD_CHILD = (1 << 15)
|
||||||
};
|
};
|
||||||
typedef enum stio_dev_pro_make_flag_t stio_dev_pro_make_flag_t;
|
typedef enum stio_dev_pro_make_flag_t stio_dev_pro_make_flag_t;
|
||||||
|
|
||||||
@ -96,10 +107,18 @@ struct stio_dev_pro_make_t
|
|||||||
{
|
{
|
||||||
int flags; /**< bitwise-ORed of stio_dev_pro_make_flag_t enumerators */
|
int flags; /**< bitwise-ORed of stio_dev_pro_make_flag_t enumerators */
|
||||||
const void* cmd;
|
const void* cmd;
|
||||||
stio_dev_pro_on_write_t on_write;
|
stio_dev_pro_on_write_t on_write; /* mandatory */
|
||||||
stio_dev_pro_on_read_t on_read;
|
stio_dev_pro_on_read_t on_read; /* mandatory */
|
||||||
|
stio_dev_pro_on_close_t on_close; /* optional */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum stio_dev_pro_ioctl_cmd_t
|
||||||
|
{
|
||||||
|
STIO_DEV_PRO_CLOSE
|
||||||
|
};
|
||||||
|
typedef enum stio_dev_pro_ioctl_cmd_t stio_dev_pro_ioctl_cmd_t;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@ -129,6 +148,11 @@ STIO_EXPORT int stio_dev_pro_timedwrite (
|
|||||||
void* wrctx
|
void* wrctx
|
||||||
);
|
);
|
||||||
|
|
||||||
|
STIO_EXPORT int stio_dev_pro_close (
|
||||||
|
stio_dev_pro_t* pro,
|
||||||
|
stio_dev_pro_sid_t sid
|
||||||
|
);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -74,7 +74,7 @@ struct stio_t
|
|||||||
{
|
{
|
||||||
stio_dev_t* head;
|
stio_dev_t* head;
|
||||||
stio_dev_t* tail;
|
stio_dev_t* tail;
|
||||||
} kdev; /* killed devices */
|
} zmbdev; /* zombie devices */
|
||||||
|
|
||||||
stio_uint8_t bigbuf[65535]; /* TODO: make this dynamic depending on devices added. device may indicate a buffer size required??? */
|
stio_uint8_t bigbuf[65535]; /* TODO: make this dynamic depending on devices added. device may indicate a buffer size required??? */
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ static int dev_sck_make_client (stio_dev_t* dev, void* ctx)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_sck_kill (stio_dev_t* dev)
|
static int dev_sck_kill (stio_dev_t* dev, int force)
|
||||||
{
|
{
|
||||||
stio_dev_sck_t* rdev = (stio_dev_sck_t*)dev;
|
stio_dev_sck_t* rdev = (stio_dev_sck_t*)dev;
|
||||||
|
|
||||||
@ -297,6 +297,8 @@ static void dev_sck_kill (stio_dev_t* dev)
|
|||||||
stio_closeasyncsck (rdev->stio, rdev->sck);
|
stio_closeasyncsck (rdev->stio, rdev->sck);
|
||||||
rdev->sck = STIO_SCKHND_INVALID;
|
rdev->sck = STIO_SCKHND_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static stio_syshnd_t dev_sck_getsyshnd (stio_dev_t* dev)
|
static stio_syshnd_t dev_sck_getsyshnd (stio_dev_t* dev)
|
||||||
|
225
stio/lib/stio.c
225
stio/lib/stio.c
@ -35,6 +35,9 @@
|
|||||||
|
|
||||||
#define IS_MSPACE(x) ((x) == STIO_MT(' ') || (x) == STIO_MT('\t'))
|
#define IS_MSPACE(x) ((x) == STIO_MT(' ') || (x) == STIO_MT('\t'))
|
||||||
|
|
||||||
|
static int schedule_kill_zombie_job (stio_dev_t* dev);
|
||||||
|
static int kill_and_free_device (stio_dev_t* dev, int force);
|
||||||
|
|
||||||
stio_t* stio_open (stio_mmgr_t* mmgr, stio_size_t xtnsize, stio_size_t tmrcapa, stio_errnum_t* errnum)
|
stio_t* stio_open (stio_mmgr_t* mmgr, stio_size_t xtnsize, stio_size_t tmrcapa, stio_errnum_t* errnum)
|
||||||
{
|
{
|
||||||
stio_t* stio;
|
stio_t* stio;
|
||||||
@ -93,16 +96,39 @@ int stio_init (stio_t* stio, stio_mmgr_t* mmgr, stio_size_t tmrcapa)
|
|||||||
|
|
||||||
void stio_fini (stio_t* stio)
|
void stio_fini (stio_t* stio)
|
||||||
{
|
{
|
||||||
/* kill all registered devices */
|
stio_dev_t* dev;
|
||||||
while (stio->dev.tail)
|
|
||||||
{
|
|
||||||
stio_killdev (stio, stio->dev.tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* purge scheduled timer jobs and kill the timer */
|
/* purge scheduled timer jobs and kill the timer */
|
||||||
stio_cleartmrjobs (stio);
|
stio_cleartmrjobs (stio);
|
||||||
STIO_MMGR_FREE (stio->mmgr, stio->tmr.jobs);
|
STIO_MMGR_FREE (stio->mmgr, stio->tmr.jobs);
|
||||||
|
|
||||||
|
/* kill all registered devices */
|
||||||
|
while (stio->dev.head)
|
||||||
|
{
|
||||||
|
stio_killdev (stio, stio->dev.head);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (stio->hdev.head)
|
||||||
|
{
|
||||||
|
stio_killdev (stio, stio->hdev.head);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clean up all zombie devices */
|
||||||
|
for (dev = stio->zmbdev.head; dev; )
|
||||||
|
{
|
||||||
|
kill_and_free_device (dev, 1);
|
||||||
|
if (stio->zmbdev.head == dev) dev = dev->dev_next;
|
||||||
|
else dev = stio->zmbdev.head;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (stio->zmbdev.tail)
|
||||||
|
{
|
||||||
|
/* if the kill method returns failure, it can leak some resource
|
||||||
|
* because the device is freed regardless of the failure when 2
|
||||||
|
* is given to kill_and_free_device(). */
|
||||||
|
kill_and_free_device (stio->zmbdev.tail, 2);
|
||||||
|
}
|
||||||
|
|
||||||
/* close the multiplexer */
|
/* close the multiplexer */
|
||||||
close (stio->mux);
|
close (stio->mux);
|
||||||
}
|
}
|
||||||
@ -434,7 +460,11 @@ static STIO_INLINE int __exec (stio_t* stio)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* kill all halted devices */
|
/* kill all halted devices */
|
||||||
while (stio->hdev.head) stio_killdev (stio, stio->hdev.head);
|
while (stio->hdev.head)
|
||||||
|
{
|
||||||
|
printf ("KILLING HALTED DEVICE %p\n", stio->hdev.head);
|
||||||
|
stio_killdev (stio, stio->hdev.head);
|
||||||
|
}
|
||||||
STIO_ASSERT (stio->hdev.tail == STIO_NULL);
|
STIO_ASSERT (stio->hdev.tail == STIO_NULL);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -542,17 +572,129 @@ stio_dev_t* stio_makedev (stio_t* stio, stio_size_t dev_size, stio_dev_mth_t* de
|
|||||||
return dev;
|
return dev;
|
||||||
|
|
||||||
oops_after_make:
|
oops_after_make:
|
||||||
dev->dev_mth->kill (dev);
|
if (kill_and_free_device (dev, 0) <= -1)
|
||||||
|
{
|
||||||
|
/* schedule a timer job that reattempts to destroy the device */
|
||||||
|
if (schedule_kill_zombie_job (dev) <= -1)
|
||||||
|
{
|
||||||
|
/* job scheduling failed. i have no choice but to
|
||||||
|
* destroy the device now.
|
||||||
|
*
|
||||||
|
* NOTE: this while loop can block the process
|
||||||
|
* if the kill method keep returning failure */
|
||||||
|
while (kill_and_free_device (dev, 1) <= -1)
|
||||||
|
{
|
||||||
|
if (stio->stopreq)
|
||||||
|
{
|
||||||
|
/* i can't wait until destruction attempt gets
|
||||||
|
* fully successful. there is a chance that some
|
||||||
|
* resources can leak inside the device */
|
||||||
|
kill_and_free_device (dev, 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return STIO_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
oops:
|
oops:
|
||||||
STIO_MMGR_FREE (stio->mmgr, dev);
|
STIO_MMGR_FREE (stio->mmgr, dev);
|
||||||
return STIO_NULL;
|
return STIO_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int kill_and_free_device (stio_dev_t* dev, int force)
|
||||||
|
{
|
||||||
|
stio_t* stio;
|
||||||
|
|
||||||
|
stio = dev->stio;
|
||||||
|
|
||||||
|
if (dev->dev_mth->kill(dev, force) <= -1)
|
||||||
|
{
|
||||||
|
if (force >= 2) goto free_device;
|
||||||
|
|
||||||
|
if (!(dev->dev_capa & STIO_DEV_CAPA_ZOMBIE))
|
||||||
|
{
|
||||||
|
dev->dev_capa |= STIO_DEV_CAPA_ZOMBIE;
|
||||||
|
|
||||||
|
/* place it at the back of the zombie device list */
|
||||||
|
if (stio->hdev.tail) stio->hdev.tail->dev_next = dev;
|
||||||
|
else stio->zmbdev.head = dev;
|
||||||
|
dev->dev_prev = stio->hdev.tail;
|
||||||
|
dev->dev_next = STIO_NULL;
|
||||||
|
stio->zmbdev.tail = dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_device:
|
||||||
|
if (dev->dev_capa & STIO_DEV_CAPA_ZOMBIE)
|
||||||
|
{
|
||||||
|
/* detach it from the zombie device list */
|
||||||
|
if (dev->dev_prev)
|
||||||
|
dev->dev_prev->dev_next = dev->dev_next;
|
||||||
|
else
|
||||||
|
stio->zmbdev.head = dev->dev_next;
|
||||||
|
|
||||||
|
if (dev->dev_next)
|
||||||
|
dev->dev_next->dev_prev = dev->dev_prev;
|
||||||
|
else
|
||||||
|
stio->zmbdev.tail = dev->dev_prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
STIO_MMGR_FREE (stio->mmgr, dev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kill_zombie_job_handler (stio_t* stio, const stio_ntime_t* now, stio_tmrjob_t* job)
|
||||||
|
{
|
||||||
|
stio_dev_t* dev = (stio_dev_t*)job->ctx;
|
||||||
|
|
||||||
|
STIO_ASSERT (dev->dev_capa & STIO_DEV_CAPA_ZOMBIE);
|
||||||
|
|
||||||
|
if (kill_and_free_device (dev, 0) <= -1)
|
||||||
|
{
|
||||||
|
if (schedule_kill_zombie_job (dev) <= -1)
|
||||||
|
{
|
||||||
|
/* i have to choice but to free up the devide by force */
|
||||||
|
while (kill_and_free_device (dev, 1) <= -1)
|
||||||
|
{
|
||||||
|
if (stio->stopreq)
|
||||||
|
{
|
||||||
|
/* i can't wait until destruction attempt gets
|
||||||
|
* fully successful. there is a chance that some
|
||||||
|
* resources can leak inside the device */
|
||||||
|
kill_and_free_device (dev, 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int schedule_kill_zombie_job (stio_dev_t* dev)
|
||||||
|
{
|
||||||
|
stio_tmrjob_t kill_zombie_job;
|
||||||
|
stio_ntime_t tmout;
|
||||||
|
|
||||||
|
stio_inittime (&tmout, 3, 0); /* TODO: take it from configuration */
|
||||||
|
|
||||||
|
STIO_MEMSET (&kill_zombie_job, 0, STIO_SIZEOF(kill_zombie_job));
|
||||||
|
kill_zombie_job.ctx = dev;
|
||||||
|
stio_gettime (&kill_zombie_job.when);
|
||||||
|
stio_addtime (&kill_zombie_job.when, &tmout, &kill_zombie_job.when);
|
||||||
|
kill_zombie_job.handler = kill_zombie_job_handler;
|
||||||
|
/*kill_zombie_job.idxptr = &rdev->tmridx_kill_zombie;*/
|
||||||
|
|
||||||
|
return stio_instmrjob (dev->stio, &kill_zombie_job) == STIO_TMRIDX_INVALID? -1: 0;
|
||||||
|
}
|
||||||
|
|
||||||
void stio_killdev (stio_t* stio, stio_dev_t* dev)
|
void stio_killdev (stio_t* stio, stio_dev_t* dev)
|
||||||
{
|
{
|
||||||
STIO_ASSERT (stio == dev->stio);
|
STIO_ASSERT (stio == dev->stio);
|
||||||
|
|
||||||
if (dev->dev_capa & STIO_DEV_CAPA_KILLED)
|
if (dev->dev_capa & STIO_DEV_CAPA_ZOMBIE)
|
||||||
{
|
{
|
||||||
STIO_ASSERT (STIO_WQ_ISEMPTY(&dev->wq));
|
STIO_ASSERT (STIO_WQ_ISEMPTY(&dev->wq));
|
||||||
goto kill_device;
|
goto kill_device;
|
||||||
@ -570,6 +712,8 @@ void stio_killdev (stio_t* stio, stio_dev_t* dev)
|
|||||||
/* delink the dev object */
|
/* delink the dev object */
|
||||||
if (dev->dev_capa & STIO_DEV_CAPA_HALTED)
|
if (dev->dev_capa & STIO_DEV_CAPA_HALTED)
|
||||||
{
|
{
|
||||||
|
/* this device is in the halted state.
|
||||||
|
* unlink it from the halted device list */
|
||||||
if (dev->dev_prev)
|
if (dev->dev_prev)
|
||||||
dev->dev_prev->dev_next = dev->dev_next;
|
dev->dev_prev->dev_next = dev->dev_next;
|
||||||
else
|
else
|
||||||
@ -582,6 +726,8 @@ void stio_killdev (stio_t* stio, stio_dev_t* dev)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* this device has not been halted.
|
||||||
|
* unlink it from the normal active device list */
|
||||||
if (dev->dev_prev)
|
if (dev->dev_prev)
|
||||||
dev->dev_prev->dev_next = dev->dev_next;
|
dev->dev_prev->dev_next = dev->dev_next;
|
||||||
else
|
else
|
||||||
@ -596,56 +742,30 @@ void stio_killdev (stio_t* stio, stio_dev_t* dev)
|
|||||||
stio_dev_watch (dev, STIO_DEV_WATCH_STOP, 0);
|
stio_dev_watch (dev, STIO_DEV_WATCH_STOP, 0);
|
||||||
|
|
||||||
kill_device:
|
kill_device:
|
||||||
/* call the kill callback function */
|
if (kill_and_free_device(dev, 0) <= -1)
|
||||||
if (dev->dev_mth->kill(dev) <= -1)
|
|
||||||
{
|
{
|
||||||
stio_tmrjob_t kill_job;
|
STIO_ASSERT (dev->dev_capa & STIO_DEV_CAPA_ZOMBIE);
|
||||||
|
if (schedule_kill_zombie_job (dev) <= -1)
|
||||||
if (!(dev->dev_capa & STIO_DEV_CAPA_KILLED))
|
|
||||||
{
|
{
|
||||||
dev->dev_capa &= STIO_DEV_CAPA_KILLED;
|
/* i have to choice but to free up the devide by force */
|
||||||
|
while (kill_and_free_device (dev, 1) <= -1)
|
||||||
/* place it at the back of the killed device list */
|
{
|
||||||
if (stio->hdev.tail) stio->hdev.tail->dev_next = dev;
|
if (stio->stopreq)
|
||||||
else stio->hdev.head = dev;
|
{
|
||||||
dev->dev_prev = stio->hdev.tail;
|
/* i can't wait until destruction attempt gets
|
||||||
dev->dev_next = STIO_NULL;
|
* fully successful. there is a chance that some
|
||||||
stio->hdev.tail = dev;
|
* resources can leak inside the device */
|
||||||
|
kill_and_free_device (dev, 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: schedule a timer job for delayed kills */
|
|
||||||
STIO_MEMSET (&kill_job, 0, STIO_SIZEOF(kill_job));
|
|
||||||
kill_job.ctx = rdev;
|
|
||||||
stio_gettime (&kill_job.when);
|
|
||||||
stio_addtime (&kill_job.when, &conn->tmout, &kill_job.when);
|
|
||||||
kill_job.handler = tmr_connect_handle;
|
|
||||||
kill_job.idxptr = &rdev->tmridx_connect;
|
|
||||||
|
|
||||||
stio_instmrjob (dev->stio, &kill_job);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (dev->dev_capa & STIO_DEV_CAPA_KILLED)
|
|
||||||
{
|
|
||||||
/* detach it from the killed device list */
|
|
||||||
if (dev->dev_prev)
|
|
||||||
dev->dev_prev->dev_next = dev->dev_next;
|
|
||||||
else
|
|
||||||
stio->kdev.head = dev->dev_next;
|
|
||||||
|
|
||||||
if (dev->dev_next)
|
|
||||||
dev->dev_next->dev_prev = dev->dev_prev;
|
|
||||||
else
|
|
||||||
stio->kdev.tail = dev->dev_prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
STIO_MMGR_FREE (stio->mmgr, dev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void stio_dev_halt (stio_dev_t* dev)
|
void stio_dev_halt (stio_dev_t* dev)
|
||||||
{
|
{
|
||||||
if (!(dev->dev_capa & STIO_DEV_CAPA_HALTED))
|
if (!(dev->dev_capa & (STIO_DEV_CAPA_HALTED | STIO_DEV_CAPA_ZOMBIE)))
|
||||||
{
|
{
|
||||||
stio_t* stio;
|
stio_t* stio;
|
||||||
|
|
||||||
@ -1015,6 +1135,11 @@ stio_errnum_t stio_syserrtoerrnum (int no)
|
|||||||
return STIO_ENFILE;
|
return STIO_ENFILE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(EAGAIN)
|
||||||
|
case EAGAIN:
|
||||||
|
return STIO_EAGAIN;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(ECONNREFUSED)
|
#if defined(ECONNREFUSED)
|
||||||
case ECONNREFUSED:
|
case ECONNREFUSED:
|
||||||
return STIO_ECONRF;
|
return STIO_ECONRF;
|
||||||
|
@ -101,10 +101,12 @@ enum stio_errnum_t
|
|||||||
STIO_ENOSUP, /* not supported */
|
STIO_ENOSUP, /* not supported */
|
||||||
STIO_EMFILE, /* too many open files */
|
STIO_EMFILE, /* too many open files */
|
||||||
STIO_ENFILE,
|
STIO_ENFILE,
|
||||||
|
STIO_EAGAIN,
|
||||||
STIO_ECONRF, /* connection refused */
|
STIO_ECONRF, /* connection refused */
|
||||||
STIO_ECONRS, /* connection reset */
|
STIO_ECONRS, /* connection reset */
|
||||||
STIO_ENOCAPA, /* no capability */
|
STIO_ENOCAPA, /* no capability */
|
||||||
STIO_ETMOUT, /* timed out */
|
STIO_ETMOUT, /* timed out */
|
||||||
|
|
||||||
|
|
||||||
STIO_EDEVMAKE,
|
STIO_EDEVMAKE,
|
||||||
STIO_EDEVERR,
|
STIO_EDEVERR,
|
||||||
@ -135,7 +137,17 @@ struct stio_dev_mth_t
|
|||||||
int (*make) (stio_dev_t* dev, void* ctx); /* mandatory. called in stio_makedev() */
|
int (*make) (stio_dev_t* dev, void* ctx); /* mandatory. called in stio_makedev() */
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
void (*kill) (stio_dev_t* dev); /* mandatory. called in stio_killdev(). called in stio_makedev() upon failure after make() success */
|
/* mandatory. called in stio_killdev(). also called in stio_makedev() upon
|
||||||
|
* failure after make() success.
|
||||||
|
*
|
||||||
|
* when 'force' is 0, the return value of -1 causes the device to be a
|
||||||
|
* zombie. the kill method is called periodically on a zombie device
|
||||||
|
* until the method returns 0.
|
||||||
|
*
|
||||||
|
* when 'force' is 1, the called should not return -1. If it does, the
|
||||||
|
* method is not called again.
|
||||||
|
*/
|
||||||
|
int (*kill) (stio_dev_t* dev, int force);
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
stio_syshnd_t (*getsyshnd) (stio_dev_t* dev); /* mandatory. called in stio_makedev() after successful make() */
|
stio_syshnd_t (*getsyshnd) (stio_dev_t* dev); /* mandatory. called in stio_makedev() after successful make() */
|
||||||
@ -262,7 +274,7 @@ enum stio_dev_capa_t
|
|||||||
STIO_DEV_CAPA_PRI_WATCHED = (1 << 14), /**< can be set only if STIO_DEV_CAPA_IN_WATCHED is set */
|
STIO_DEV_CAPA_PRI_WATCHED = (1 << 14), /**< can be set only if STIO_DEV_CAPA_IN_WATCHED is set */
|
||||||
|
|
||||||
STIO_DEV_CAPA_HALTED = (1 << 15),
|
STIO_DEV_CAPA_HALTED = (1 << 15),
|
||||||
STIO_DEV_CAPA_KILLED = (1 << 16)
|
STIO_DEV_CAPA_ZOMBIE = (1 << 16)
|
||||||
};
|
};
|
||||||
typedef enum stio_dev_capa_t stio_dev_capa_t;
|
typedef enum stio_dev_capa_t stio_dev_capa_t;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user