/*----------------------------------------------------------------------+*/ 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; }
/*----------------------------------------------------------------------+*/ int pre_fork_channel_object(SPC_Channel_Ptr channel) /*----------------------------------------------------------------------+*/ { Wire *wirelist; int flag=0; /* Set all wires to be "data ready" */ for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) { wirelist->flags |= SPCIO_DATA; flag=1; } /* Move to the "Running & (possibly) data ready" state */ SPC_Change_State(channel, 0, flag, 1); return(TRUE); }
/* 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; }
/*----------------------------------------------------------------------+*/ int read_pty_channel_object(SPC_Channel_Ptr channel, int connector, /* STDOUT or STDERR */ XeString buffer, int nbytes) /*----------------------------------------------------------------------+*/ #ifdef __hpux_pty { int result, select_value; struct fd_set read_mask, except_mask; int fd=channel->file_descs[connector]; struct request_info req_info; struct timeval timeout, *timeptr; int i; call_parent_method(channel, read, (channel, connector, buffer, nbytes), result); if(result==SPC_ERROR) return(SPC_ERROR); if(!IS_SPCIO_DATA(channel->wires[connector]->flags)) return(0); FD_ZERO(&read_mask); FD_ZERO(&except_mask); FD_SET(fd, &read_mask); FD_SET(fd, &except_mask); if(channel->close_timeout) { timeout.tv_sec=channel->close_timeout; timeout.tv_usec=0; timeptr = (&timeout); } else timeptr=NULL; do select_value=select(fd+1, &read_mask, NULL, &except_mask, timeptr); while(select_value==ERROR && errno==EINTR); if(select_value==ERROR) { SPC_Error(SPC_Bad_Select); return(SPC_ERROR); } /* If there is anything to read, read it & return */ IS_FD_SET(&read_mask, result); if(result) { do { result = read(fd, buffer, nbytes); } while (result<0 && errno == EINTR); if(result==ERROR) { SPC_Error(SPC_Reading); return(SPC_ERROR); } return(result); } /* Nothing to read. We either timed out or got an exception. */ if(select_value != 0) { /* We got an exception */ ioctl(fd, TIOCREQGET, &req_info); /* Clear the request (Not really necessary in the case of a close, but do it anyway) */ ioctl(fd, TIOCREQSET, &req_info); } if((select_value == 0) || (req_info.request == TIOCCLOSE)) { /* Close, disable trapping on this fd & return EOF. We regard a timeout as being the same as a close. */ SPC_Disable_Trapping(fd); SPC_Change_State(channel, connector, 0, -1); return(0); } else /* Otherwise (open or IOCTL), return -1 */ return(EXCEPT_FLAG); }