6 lines of codes were added to shell.c to remove all these zombies.
about some definitions :
a zombie is a process that wants to terminate but cannot warn its dead father, so it is kept in system tables endlessly.
to clean up properly, the father's got to wait the ending of its child before exiting.
cheers,
yves:
Yves Degoyon wrote:
yes, I am using netsend/receive, but the program on the other end, piping the pdreceive into the program and forwarding the output via pdsend back to PD, needs to be started. If this were possible from shell, or otherwise from inside PD, then I could have small units that started the piping chain within the PD patch rather than having to start it myself from the command line.
i've made a little test script ( here attached ) that does the lauching of pdreceive and then communicates with pd.
it DOES stay alive and the problem is rather that the process is not destroyed when i destroy the shell object, that's why <defunct> processes appear ( the father ( shell object ) is dead and the script is still alive ).
then you cannot launch a new instance of your script if the former one holds an exclusive ressource ( like a port number ).
in my example, this luckily works but this is surely unclean...
cheers,
yves
/* (C) Guenter Geiger geiger@epy.co.at */
#include <m_pd.h> #ifdef NT #pragma warning( disable : 4244 ) #pragma warning( disable : 4305 ) #endif
#include <unistd.h> #include <stdio.h> #include <sys/types.h> #include <signal.h>
/* ------------------------ shell ----------------------------- */
#define INBUFSIZE 1024
static t_class *shell_class;
typedef struct _shell { t_object x_obj; int x_echo; char *sr_inbuf; int sr_inhead; int sr_intail; void* x_binbuf; int fdpipe[2]; int pid; } t_shell;
void shell_bang(t_shell *x) { post("shell : bang"); }
#if 1 static void shell_doit(void *z, t_binbuf *b) { t_atom messbuf[1024]; t_shell *x = (t_shell *)z; int msg, natom = binbuf_getnatom(b); t_atom *at = binbuf_getvec(b);
for (msg = 0; msg < natom;)
{
int emsg;
for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA
&& at[emsg].a_type != A_SEMI; emsg++)
;
if (emsg > msg)
{
int i;
for (i = msg; i < emsg; i++)
if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM)
{
pd_error(x, "netreceive: got dollar sign in message");
goto nodice;
}
if (at[msg].a_type == A_FLOAT)
{
if (emsg > msg + 1)
outlet_list(x->x_obj.ob_outlet, 0, emsg-msg, at + msg);
else outlet_float(x->x_obj.ob_outlet, at[msg].a_w.w_float);
}
else if (at[msg].a_type == A_SYMBOL)
outlet_anything(x->x_obj.ob_outlet, at[msg].a_w.w_symbol,
emsg-msg-1, at + msg + 1);
}
nodice:
msg = emsg + 1;
}
}
void shell_read(t_shell *x, int fd) { char buf[INBUFSIZE]; t_binbuf* bbuf = binbuf_new(); int i; int readto = (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1); int ret;
ret = read(fd, buf,INBUFSIZE);
buf[ret] = '\0';
for (i=0;i<ret;i++)
if (buf[i] == '\n') buf[i] = ';';
if (ret < 0)
{
error("shell: pipe read error");
sys_rmpollfn(fd);
x->fdpipe[0] = -1;
close(fd);
return;
}
else if (ret == 0)
{
post("EOF on socket %d\n", fd);
sys_rmpollfn(fd);
x->fdpipe[0] = -1;
close(fd);
return;
}
else
{
int natom;
t_atom *at;
binbuf_text(bbuf, buf, strlen(buf));
natom = binbuf_getnatom(bbuf);
at = binbuf_getvec(bbuf);
shell_doit(x,bbuf);
}
binbuf_free(bbuf);
}
#endif
static void shell_anything(t_shell *x, t_symbol *s, int ac, t_atom *at) { int i; char* argv[20];
argv[0] = s->s_name;
if (x->fdpipe[0] != -1) {
close(x->fdpipe[0]);
close(x->fdpipe[1]);
sys_rmpollfn(x->fdpipe[0]);
x->fdpipe[0] = -1;
x->fdpipe[1] = -1;
kill(x->pid,SIGKILL);
}
for (i=1;i<=ac;i++) {
argv[i] = atom_getsymbolarg(i-1,ac,at)->s_name;
/* post("argument %s",argv[i]);*/
}
argv[i] = 0;
if (pipe(x->fdpipe) < 0)
error("unable to create pipe");
sys_addpollfn(x->fdpipe[0],shell_read,x);
if (!(x->pid = fork())) {
/* reassign stdout */
dup2(x->fdpipe[1],1);
execvp(s->s_name,argv);
exit(0);
}
if (x->x_echo)
outlet_anything(x->x_obj.ob_outlet, s, ac, at);
}
static void shell_free(t_shell* x) { t_int status;
post( "shell : cleaning up...( pid=%d )", x->pid );
if ( kill ( x->pid, SIGKILL ) == -1 )
{
post( "shell : couldn't not kill child on exit. some zombies ????" );
perror( "kill" );
}
if ( waitpid( x->pid, &status, 0 ) == -1 )
{
post( "shell : abnormal terminsation" );
perror( "waitpid" );
}
binbuf_free(x->x_binbuf);
post( "shell : done." );
}
static void *shell_new(void) { t_shell *x = (t_shell *)pd_new(shell_class);
x->x_echo = 0;
x->fdpipe[0] = -1;
x->fdpipe[1] = -1;
x->sr_inhead = x->sr_intail = 0;
if (!(x->sr_inbuf = (char*) malloc(INBUFSIZE))) bug("t_shell");;
x->x_binbuf = binbuf_new();
outlet_new(&x->x_obj, &s_list);
return (x);
}
void shell_setup(void) { shell_class = class_new(gensym("shell"), (t_newmethod)shell_new, (t_method)shell_free, sizeof(t_shell), 0, 0); class_addbang(shell_class,shell_bang); class_addanything(shell_class, shell_anything); }