#include #include #include #include #include #include #include #include #include "../tlmplib/tlmplib.h" #include "tlmpdia.h" #include "tlmpdia.m" void *forktmp_mapshare (int len) { void *ret = mmap (NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0); if (ret == NULL){ tlmp_error (MSG_U(E_CANTMMAP,"Can't allocate shared memory\n")); } return ret; } void forktmp_unmap (void *pt, int len) { munmap (pt,len); } struct _F_forktmp_private{ int fdout; int fdin; pid_t pid; bool end; _F_forktmp_private(){ pid = (pid_t)-1; fdout = -1; end = false; } }; struct forkrec{ enum {RES_NONE,RES_END,RES_JOIN} res; int state; forkrec(); }; forkrec::forkrec() { res = RES_NONE; state = 0; } void _F_forktmp::kill() { ::kill (priv->pid,SIGTERM); } void _F_forktmp::join(int state) { forkrec rec; rec.res = forkrec::RES_JOIN; rec.state = state; write (priv->fdout,&rec,sizeof(rec)); read (priv->fdin,&rec,sizeof(rec)); } void _F_forktmp::message (bool &end) { end = true; } void _F_forktmp::joining (bool &, int) { tlmp_error (MSG_U(E_NOJOINING,"Programming error\n" "Child request a join, no joining functag\n")); } void _F_forktmp::timeout (bool &end, int) { end = true; } void _F_forktmp::failed () { tlmp_error (MSG_U(E_FORKFAILED ,"Programming error: Child process %d failed\n") ,priv->pid); } int forktmp (_F_forktmp &c, int timeout, PRIVATE_MESSAGE &endmsg) { _F_forktmp_private priv; c.priv = &priv; int ret = -1; int fds1[2],fds2[2]; if (pipe(fds1)==-1){ tlmp_error (MSG_U(E_CANTPIPE,"Can't setup the internal pipe to control subprocess\n")); }else if (pipe(fds2)==-1){ tlmp_error (MSG_R(E_CANTPIPE)); close (fds1[0]); close (fds1[1]); }else{ priv.fdout = fds1[1]; priv.fdin = fds2[0]; priv.pid = fork(); if (priv.pid == 0){ close (fds1[0]); close (fds2[1]); c.task(); forkrec rec; rec.res = forkrec::RES_END; write (fds1[1],&rec,sizeof(rec)); _exit (0); }else if (priv.pid == (pid_t)-1){ tlmp_error (MSG_U(E_CANTFORK,"Can't fork a new process (%s)\n") ,strerror(errno)); close (fds1[1]); close (fds2[0]); }else{ close (fds1[1]); close (fds2[0]); time_t start = time(NULL); while (!priv.end){ fd_set fdin; FD_ZERO (&fdin); FD_SET (fds1[0],&fdin); int ok = diagui_select (fds1[0]+1,&fdin,timeout,endmsg); if (ok == 0){ int duration = time(NULL)-start; c.timeout(priv.end,duration); }else if (ok > 0){ forkrec rec; int len = read (fds1[0],&rec,sizeof(rec)); if (len != sizeof(rec)){ c.failed(); priv.end = true; ret = -1; }else if(rec.res == forkrec::RES_END){ ret = 0; priv.end = true; }else if(rec.res == forkrec::RES_JOIN){ c.joining (priv.end,rec.state); if (!priv.end){ write (fds2[1],&rec,sizeof(rec)); } } }else if (dialog_testmessage(endmsg)){ c.message(priv.end); } } c.kill(); } close (fds1[0]); close (fds2[1]); } return ret; } int forktmp (_F_forktmp &c, int timeout) { PRIVATE_MESSAGE endmsg; return forktmp (c,timeout,endmsg); } int forktmp (_F_forktmp &c) { PRIVATE_MESSAGE endmsg; return forktmp (c,-1,endmsg); }