📄 command.c
字号:
} else if ( ndead_childs > 0 ) { /* * This is problematic. The number of processes that were promised as * "dead" on entry to this function is not actually the number of * processes that are dead! * * NOTE: It is OK for r->ndead_childs > 0, as r->ndead_childs could be * externally modified while we are in this function. * * We should only get here when one of our child processes that is NOT * running in a tab dies. For instance, when we print something with our * "PrintPipe" macro. If we get here for any other reason, we're in deep * trouble. */ rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND, "Spurious dead child signal received\n")); /* * We should reset r->ndead_childs to 0. But there is a possible race * condition with doing that. Suppose we received a dead child signal * *after* looping over all childs, but just before getting here! * * To avoid this we only reduce r->ndead_childs by the number of * processes we failed to catch as dead. Further, when we get EIO errors * reading from a child, we call this function to see if the child is * dead or not. */ r->ndead_childs -= ndead_childs; } rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND, "Exit rxvt_mark_dead_childs(): %d children are dead\n", r->ndead_childs));}/* * Cleans out tabs which have died but have not been cleaned up. (i.e. dead && * hold == 1) * * NOTE: This function MUST NOT be called from rxvt_cmd_getc(), because it could * redirect command buffer input of the tabs. *//* INTPROTO */voidrxvt_clean_cmd_page (rxvt_t* r){ int i; rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND, "rxvt_clean_cmd_page()\n" )); if( r->ndead_childs ) rxvt_mark_dead_childs( r ); /* * We had better not get here unless we need to clean up dead children. Make * sure we don't proceed when we receive spurious dead child messages (e.g. * from when the print pipe dies). */ if( !r->cleanDeadChilds ) return; /* * We start from the last child because we need to move ahead after * removing dead child. This makes it much safer. * * Why do we need to restart dead value from LTAB(r) again? Because a * child may have died when we do something following and changed the * value of r->ndead_childs! This child may be later than any dead children * we have examined. */ for (i = LTAB(r); i >= 0; i--) { if( PVTS(r, i)->dead && PVTS(r, i)->hold == 1 ) { rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND, "Tab %d exit %s (status %d). holdOption: %d\n", i, WIFEXITED(PVTS(r,i)->status) ? "success" : "failure", PVTS(r,i)->status, PVTS(r,i)->holdOption)); /* * Process in tab i has died, and needs to be cleaned up. */ if( SHOULD_HOLD( r, i ) ) { const int maxLen = 1024; const char *msg; rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND, "Hold child %d after it died\n", i)); /* increase hold number, so next iteration will skip it */ PVTS(r, i)->hold++; /* * Process any pending data from the child. */ do { unsigned char *last_escfail = NULL; /* * Process information in the child's output buffer. */ while( PVTS(r, i)->cmdbuf_ptr < PVTS(r, i)->cmdbuf_endp ) { rxvt_process_getc( r, i, *(PVTS(r,i)->cmdbuf_ptr++) ); /* Incomplete escape sequence. */ if( PVTS(r, i)->cmdbuf_escfail ) { /* * See if reading from the child's fd will complete * this escape seqeunce. */ if( IS_NULL( last_escfail ) ) last_escfail = PVTS(r, i)->cmdbuf_escfail; else { /* Really incomplete escape sequence */ rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND, "Incomplete escape sequence '%.*s'\n", PVTS(r, i)->cmdbuf_escfail - PVTS(r, i)->cmdbuf_escstart + 1, PVTS(r, i)->cmdbuf_escstart+1)); SET_NULL( last_escfail ); SET_NULL( PVTS(r, i)->cmdbuf_escstart ); SET_NULL( PVTS(r, i)->cmdbuf_escfail ); /* Skip the escape char */ PVTS(r, i)->cmdbuf_ptr++; } } /* if( PVTS(r, i)->cmdbuf_escfail ) */ } /* * Write out pending data in the child's input buffer. */ if (PVTS(r, i)->v_bufstr < PVTS(r, i)->v_bufptr) rxvt_cmd_write(r, i, NULL, 0); /* Make place for new data */ rxvt_check_cmdbuf( r, i ); /* Read any remaining data from childs fd */ rxvt_read_child_cmdfd( r, i, BUFSIZ - 1 - (PVTS(r, i)->cmdbuf_endp - PVTS(r, i)->cmdbuf_base) ); } while( rxvt_cmdbuf_has_input( r, i) ); /* * print holdExitText on screen if defined. */ msg = getProfileOption( r, PVTS(r,i)->profileNum, Rs_holdExitTxt ); if( NOT_NULL( msg ) && *msg ) { unsigned char buffer[maxLen]; int len; rxvt_percent_interpolate( r, i, msg, STRLEN(msg), (char*) buffer, maxLen ); len = rxvt_str_escaped( (char*) buffer ); rxvt_cmd_write(r, i, buffer, len ); if( PVTS(r, i)->cmdbuf_ptr < PVTS(r, i)->cmdbuf_endp ) rxvt_process_getc( r, i, *(PVTS(r,i)->cmdbuf_ptr++) ); } /* * Update title to show tab has finished. */ msg = getProfileOption( r, PVTS(r,i)->profileNum, Rs_holdExitTtl ); if( NOT_NULL( msg ) && *msg ) { unsigned char tabTitle[maxLen]; rxvt_percent_interpolate( r, i, msg, STRLEN(msg), (char*) tabTitle, maxLen ); rxvt_str_escaped( (char*) tabTitle ); rxvt_tabbar_set_title( r, i, tabTitle ); } } /* if( SHOULD_HOLD( r, i ) ) */ else rxvt_remove_page( r, i ); } } /* for(i) */ r->cleanDeadChilds = 0; /* Dead child cleanup complete. */}/* Returns true if there is input pending in PVTS(r, page)->cmdbuf *//* INTPROTO */int static inlinerxvt_cmdbuf_has_input( rxvt_t *r, int page ){ return PVTS(r, page)->cmdbuf_escfail ? PVTS(r, page)->cmdbuf_escfail < PVTS(r, page)->cmdbuf_endp : PVTS(r, page)->cmdbuf_ptr < PVTS(r, page)->cmdbuf_endp;}/* * Find a tab with some output, and return it. * * Bug #1102791 (Carsten Menke): A really busy tab could starve all others. So * use a round robin to go through all tabs. *//* INTPROTO */intrxvt_find_cmd_child (rxvt_t* r){ register int k; static int lastProcessed = 0; /* tab we processed last time */ rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND, "rxvt_find_cmd_child()\n" )); /* * See if the active tab has input before anything else. */ if( rxvt_cmdbuf_has_input( r, ATAB(r) ) ) return ATAB(r); /* * Now look for data from other tabs. Remember the tab we found data from so * that we can start from the next tab on the next call to this function. */ if( lastProcessed > LTAB(r) ) /* Sanity check */ lastProcessed = LTAB(r); /* start from the next tab of last processed tab */ k = lastProcessed + 1; do { if( k > LTAB(r) ) /* round-robin */ k = 0; assert( PVTS(r, k)->cmdbuf_base <= PVTS(r, k)->cmdbuf_endp ); /* already have something in some page's buffer */ if( rxvt_cmdbuf_has_input(r, k) ) { lastProcessed = k; return k; } } while (k++ != lastProcessed); /* until we hit the last child again */ return -1; /* not found */}/* INTPROTO */voidrxvt_check_cmdbuf (rxvt_t* r, int page){ assert( PVTS(r, page)->cmdbuf_base <= PVTS(r, page)->cmdbuf_endp ); if( IS_NULL( PVTS(r, page)->cmdbuf_escstart ) && PVTS(r, page)->cmdbuf_ptr == PVTS(r, page)->cmdbuf_endp ) { /* * If there is no data in the buffer, reset it to the beginning * of the buffer. */ PVTS(r, page)->cmdbuf_ptr = PVTS(r, page)->cmdbuf_endp = PVTS(r, page)->cmdbuf_base; } else if( (PVTS(r, page)->cmdbuf_endp - PVTS(r, page)->cmdbuf_base) == (BUFSIZ-1) && ( PVTS(r, page)->cmdbuf_escstart ? (PVTS(r, page)->cmdbuf_escstart > PVTS(r,page)->cmdbuf_base) : (PVTS(r, page)->cmdbuf_ptr > PVTS(r, page)->cmdbuf_base) ) ) { /* * If there is space at beginning of the buffer, but not space at the * end of the buffer, move the content of buffer forward to free space */ unsigned char *start; unsigned int n, len; start = PVTS(r, page)->cmdbuf_escstart ? PVTS(r, page)->cmdbuf_escstart : PVTS(r, page)->cmdbuf_ptr; n = start - PVTS(r, page)->cmdbuf_base; len = PVTS(r, page)->cmdbuf_endp - start; assert( n == BUFSIZ - 1 - len ); assert( start < PVTS(r, page)->cmdbuf_endp ); MEMMOVE( PVTS(r, page)->cmdbuf_base, start, len ); PVTS(r, page)->cmdbuf_ptr -= n; PVTS(r, page)->cmdbuf_endp -= n; if( PVTS(r, page)->cmdbuf_escstart ) PVTS(r, page)->cmdbuf_escstart -= n; if( PVTS(r, page)->cmdbuf_escfail ) PVTS(r, page)->cmdbuf_escfail -= n; }}/* * This function returns the number of bytes being read from a child *//* INTPROTO */intrxvt_read_child_cmdfd (rxvt_t* r, int page, unsigned int count){ int n = 0, bread = 0; struct timeval tp; while( count ) { int readErrno; rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND, "read maximal %u bytes\n", count)); /* * 2006-08-23 gi1242: O_NDELAY is set here, so we need not worry about * calls to read() blocking. */ errno = PVTS(r, page)->gotEIO = 0; n = read( PVTS(r, page)->cmd_fd, PVTS(r, page)->cmdbuf_endp, count ); readErrno = errno; rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND, "read %d bytes\n", n)); if (n > 0) { /* Update count and buffer pointer */ count -= n; bread += n; PVTS(r, page)->cmdbuf_endp += n; } else if (0 == n) { /* rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND, "Should not happen?\n")); */ /* 2006-08-23 gi1242: Could happen if we have no more data. */ break; } else /* if (n < 0) */ { /* * We do not update count and buffer pointer and continue * trying read more data in the next loop iteration. */ rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND, "%s\n", strerror(readErrno))); assert( readErrno != EBADF && readErrno != EFAULT && readErrno != EISDIR ); /* See if this process is dead */ switch (readErrno) { case EIO: r->gotEIO = PVTS(r, page)->gotEIO = 1; case EINTR: rxvt_mark_dead_childs(r); break; } /* * 2006-08-31 gi1242: Old code would only break out on EAGAIN or * EINVAL. */ break; } } /* while (count) */ if (bread != 0) { gettimeofday( &tp, NULL); rxvt_dbgmsg ((DBG_DEBUG, DBG_COMMAND, "output produced on epoch %i\n", tp.tv_sec)); } PVTS(r, page)->monitor_nbytes_read += bread; PVTS(r, page)->nbytes_last_read = bread; return bread;}/* INTPROTO */voidrxvt_monitor_tab(rxvt_t* r,int i){ struct timeval tp; struct timeval monitor_timeout_time; short execute_action = 0; int monitor_timeout = 2000; /* return, if no monitoring is activated */ if ((IS_NULL(&PVTS(r, i)->monitor_tab)) || (PVTS(r, i)->monitor_tab == TAB_MON_OFF) || (PVTS(r, i)->monitor_tab == TAB_MON_NOTIFICATION)) return; monitor_timeout_time = PVTS(r, i)->monitor_start; /* set configured monitor_timeout milliseconds , if configured */ if( r->h->rs[Rs_monitorTimeout] ) monitor_timeout = atoi( r->h->rs[Rs_monitorTimeout] ); monitor_timeout_time.tv_sec += (int) monitor_timeout/1000; monitor_timeout_time.tv_usec += (monitor_timeout - (((int) monitor_timeout/1000) * 1000)) * 1000; /* get current epoch time */ gettimeofday( &tp, NULL); /* monitor-type "AUTO" : determine which type of monitoring is needed */ if ((PVTS(r, i)->monitor_tab == TAB_MON_AUTO) && (timercmp(&monitor_timeout_time,&tp, <))) { if(PVTS(r, i)->monitor_nbytes_read > 0) { PVTS(r, i)->monitor_tab = TAB_MON_INACTIVITY; rxvt_msg (DBG_INFO, DBG_MACROS, "Macro MonitorTab: decided to monitor inactivity on tab %i", i); } else { PVTS(r, i)->monitor_tab = TAB_MON_ACTIVITY; rxvt_msg (DBG_INFO, DBG_MACROS, "Macro MonitorTab: decided to monitor activity on tab %i", i); } PVTS(r, i)->monitor_nbytes_read = 0 ; PVTS(r, i)->monitor_start = tp; } /* monitor-type "INACTIVITY" : detect inactivity */ else if ((PVTS(r, i)->monitor_tab == TAB_MON_INACTIVITY) && (timercmp(&monitor_timeout_time,&tp, <))) { /* inactivity detected */ if (PVTS( r, i)->monitor_nbytes_read == 0) { rxvt_msg (DBG_INFO, DBG_MACROS, "Macro MonitorTab: detected inactivity on tab %i", i); execute_action = 1; } /* activity detected, restarting monitoring */ else { rxvt_msg (DBG_DEBUG, DBG_MACROS, "Macro MonitorTab: NOT detected inactivity on tab %i / %i ", i, PVTS(r,i)->monitor_nbytes_read); PVTS(r, i)->monitor_start = tp; PVTS(r, i)->monitor_nbytes_read = 0; } } /* monitor-type "ACTIVITY" : detect activity */ else if ((PVTS(r, i)->monitor_tab == TAB_MON_ACTIVITY) && (PVTS( r, i)->monitor_nbytes_read != 0)) { rxvt_msg (DBG_INFO, DBG_MACROS, "Macro MonitorTab: detected activity on tab %i", i); execute_action = 1; } /* stop execution of this function if no activity/inactivity * needs to be notified
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -