/*----------------------------------------------------------------------+*/ void SPC_Channel_Terminated(SPC_Channel_Ptr channel) /*----------------------------------------------------------------------+*/ { int type, cause; SPC_Change_State(channel, 0, -1, 0); /* Set the close timeout. If we are on a PTY, we will return after two seconds if we are waiting for EOF */ channel->close_timeout=2; if(IS_DATA(channel) && (channel->Input_Handler)) { while(IS_SPCIO_DATA(channel->wires[STDOUT]->flags)) SPC_Input_Handler(channel, STDOUT); while(IS_SPCIO_DATA(channel->wires[STDERR]->flags)) SPC_Input_Handler(channel, STDERR); } if(channel->Terminate_Handler) { XeSPCGetProcessStatus(channel, &type, &cause); (* channel->Terminate_Handler) (channel, channel->pid, type, cause, channel->Terminate_Data); } channel->close_timeout=0; }
/* This is the right way according to the Spec 1170 */ void SPC_Child_Terminated(int i) /*----------------------------------------------------------------------+*/ { /* This catches signals for sub-process termination */ int type, cause, status; pid_t wait_pid, pid; SPC_Channel_Ptr channel; protocol_request req, *prot; buffered_data data, *pdata; int length; int indx; int saved_errno = errno; prot = (&req); pdata = (&data); prot->dataptr=pdata; wait_pid = -1; while(pid = waitpid(wait_pid, &status, WNOHANG)) { if((pid == -1 && errno == ECHILD) || pid == 0) { /* no more children. Return */ errno = saved_errno; return; } /* Okay, we got the process ID of a terminated child. Find the channel associated with this PID. */ channel=SPC_Find_PID(pid); #ifdef DEBUG fprintf(stderr, (XeString)"got SIGCHLD, pid: %d, channel: %p\n", pid, channel); #endif if(!channel) { continue; } _DtSvcProcessLock(); /* * Look for this process in the pid list. If found, mark it * as done. */ if (SPC_pid_list != NULL) { for (indx=0; SPC_pid_list[indx] != NULL; indx++) if (SPC_pid_list[indx] == pid) { SPC_pid_list[indx] = SPCD_DEAD_PROCESS; break; } } _DtSvcProcessUnlock(); /* We have the channel. Mark it as being closed. */ channel->status = status; /* If we this channel is set up for synchronous termination, write the protocol request to record that this guy died. Otherwise, call the termination handler directly. */ if(IS_SPCIO_SYNC_TERM(channel->IOMode)) { /* This code is basically what SPC_Write_Protocol_Request does. It is replicated here because a call to SPC_W_P_R would have to be re-enterant if we called it here, and SPC_W_P_R is not re-enterant at this time. */ SPC_Reset_Protocol_Ptr(prot, channel, APPLICATION_DIED, 0); pdata->len=WRITE_APPLICATION_DIED(pdata, status); length=WRITE_HEADER(pdata, channel->cid, prot->request_type, pdata->len, 0); pdata->data[length]=(XeChar)' '; length=pdata->len+REQUEST_HEADER_LENGTH; if(write(write_terminator->sid, pdata->data, length)==ERROR) SPC_Error(SPC_Internal_Error); pdata->offset=REQUEST_HEADER_LENGTH; print_protocol_request((XeString) (XeString)" <-- INTERNAL APPLICATION_DIED", prot); } else { SPC_Change_State(channel, NULL, -1, 0); if(channel->Terminate_Handler) { XeSPCGetProcessStatus(channel, &type, &cause); (* channel->Terminate_Handler) (channel, channel->pid, type, cause, channel->Terminate_Data); } } /* Loop around & get another PID */ } errno = saved_errno; }