void RPC2_DispatchProcess() { struct timeval tv; int fd; while ((fd = rpc2_MorePackets()) != -1) rpc2_ProcessPacket(fd); /* keep current time from being too inaccurate */ (void)FT_GetTimeOfDay(&tv, (struct timezone *)0); /* also check for timed-out events, using current time */ rpc2_ExpireEvents(); LWP_DispatchProcess(); }
int OpenLog(const char *fileName) { /* * This function should allow various libraries that inconsistently * use stdout/stderr to all go to the same place */ int tempfd, isfifo = 0; char oldName[MAXPATHLEN]; struct timeval Start; struct tm *TimeFields; char FileName[MAXPATHLEN]; #ifndef AFS_NT40_ENV struct stat statbuf; if (serverLogSyslog) { openlog(serverLogSyslogTag, LOG_PID, serverLogSyslogFacility); return (0); } /* Support named pipes as logs by not rotating them */ if ((lstat(fileName, &statbuf) == 0) && (S_ISFIFO(statbuf.st_mode))) { isfifo = 1; } #endif if (mrafsStyleLogs) { time_t t; struct stat buf; FT_GetTimeOfDay(&Start, 0); t = Start.tv_sec; TimeFields = localtime(&t); if (fileName) { if (strncmp(fileName, (char *)&ourName, strlen(fileName))) strcpy((char *)&ourName, (char *)fileName); } makefilename: afs_snprintf(FileName, MAXPATHLEN, "%s.%d%02d%02d%02d%02d%02d", ourName, TimeFields->tm_year + 1900, TimeFields->tm_mon + 1, TimeFields->tm_mday, TimeFields->tm_hour, TimeFields->tm_min, TimeFields->tm_sec); if(lstat(FileName, &buf) == 0) { /* avoid clobbering a log */ TimeFields->tm_sec++; goto makefilename; } if (!isfifo) renamefile(fileName, FileName); /* don't check error code */ tempfd = open(fileName, O_WRONLY | O_TRUNC | O_CREAT | O_APPEND | (isfifo?O_NONBLOCK:0), 0666); } else { strcpy(oldName, fileName); strcat(oldName, ".old"); /* don't check error */ if (!isfifo) renamefile(fileName, oldName); tempfd = open(fileName, O_WRONLY | O_TRUNC | O_CREAT | (isfifo?O_NONBLOCK:0), 0666); } if (tempfd < 0) { printf("Unable to open log file %s\n", fileName); return -1; } /* redirect stdout and stderr so random printf's don't write to data */ (void)freopen(fileName, "a", stdout); (void)freopen(fileName, "a", stderr); #ifdef HAVE_SETVBUF setvbuf(stderr, NULL, _IONBF, 0); #else setbuf(stderr, NULL); #endif #if defined(AFS_PTHREAD_ENV) MUTEX_INIT(&serverLogMutex, "serverlog", MUTEX_DEFAULT, 0); #endif /* AFS_PTHREAD_ENV */ serverLogFD = tempfd; if (mrafsStyleLogs) { FSLog("Running version %s\n", cml_version_number +4); } return 0; } /*OpenLog */
int main(int argc, char **argv) { afs_int32 code; struct rx_securityClass **securityClasses; afs_int32 numClasses; struct rx_service *service; struct ktc_encryptionKey tkey; int rxpackets = 100; int rxJumbograms = 0; /* default is to send and receive jumbograms. */ int rxMaxMTU = -1; int bufSize = 0; /* temp variable to read in udp socket buf size */ afs_uint32 host = ntohl(INADDR_ANY); char *auditFileName = NULL; VolumePackageOptions opts; #ifdef AFS_AIX32_ENV /* * The following signal action for AIX is necessary so that in case of a * crash (i.e. core is generated) we can include the user's data section * in the core dump. Unfortunately, by default, only a partial core is * generated which, in many cases, isn't too useful. */ struct sigaction nsa; sigemptyset(&nsa.sa_mask); nsa.sa_handler = SIG_DFL; nsa.sa_flags = SA_FULLDUMP; sigaction(SIGABRT, &nsa, NULL); sigaction(SIGSEGV, &nsa, NULL); #endif osi_audit_init(); osi_audit(VS_StartEvent, 0, AUD_END); /* Initialize dirpaths */ if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) { #ifdef AFS_NT40_ENV ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0); #endif fprintf(stderr, "%s: Unable to obtain AFS server directory.\n", argv[0]); exit(2); } TTsleep = TTrun = 0; /* parse cmd line */ for (code = 1; code < argc; code++) { if (strcmp(argv[code], "-log") == 0) { /* set extra logging flag */ DoLogging = 1; } else if (strcmp(argv[code], "-help") == 0) { goto usage; } else if (strcmp(argv[code], "-rxbind") == 0) { rxBind = 1; } else if (strcmp(argv[code], "-allow-dotted-principals") == 0) { rxkadDisableDotCheck = 1; } else if (strcmp(argv[code], "-d") == 0) { if ((code + 1) >= argc) { fprintf(stderr, "missing argument for -d\n"); return -1; } debuglevel = atoi(argv[++code]); LogLevel = debuglevel; } else if (strcmp(argv[code], "-p") == 0) { lwps = atoi(argv[++code]); if (lwps > MAXLWP) { printf("Warning: '-p %d' is too big; using %d instead\n", lwps, MAXLWP); lwps = MAXLWP; } } else if (strcmp(argv[code], "-auditlog") == 0) { auditFileName = argv[++code]; } else if (strcmp(argv[code], "-audit-interface") == 0) { char *interface = argv[++code]; if (osi_audit_interface(interface)) { printf("Invalid audit interface '%s'\n", interface); return -1; } } else if (strcmp(argv[code], "-nojumbo") == 0) { rxJumbograms = 0; } else if (strcmp(argv[code], "-jumbo") == 0) { rxJumbograms = 1; } else if (!strcmp(argv[code], "-rxmaxmtu")) { if ((code + 1) >= argc) { fprintf(stderr, "missing argument for -rxmaxmtu\n"); exit(1); } rxMaxMTU = atoi(argv[++code]); if ((rxMaxMTU < RX_MIN_PACKET_SIZE) || (rxMaxMTU > RX_MAX_PACKET_DATA_SIZE)) { printf("rxMaxMTU %d invalid; must be between %d-%" AFS_SIZET_FMT "\n", rxMaxMTU, RX_MIN_PACKET_SIZE, RX_MAX_PACKET_DATA_SIZE); exit(1); } } else if (strcmp(argv[code], "-sleep") == 0) { sscanf(argv[++code], "%d/%d", &TTsleep, &TTrun); if ((TTsleep < 0) || (TTrun <= 0)) { printf("Warning: '-sleep %d/%d' is incorrect; ignoring\n", TTsleep, TTrun); TTsleep = TTrun = 0; } } else if (strcmp(argv[code], "-mbpersleep") == 0) { sscanf(argv[++code], "%d", &MBperSecSleep); if (MBperSecSleep < 0) MBperSecSleep = 0; } else if (strcmp(argv[code], "-udpsize") == 0) { if ((code + 1) >= argc) { printf("You have to specify -udpsize <integer value>\n"); exit(1); } sscanf(argv[++code], "%d", &bufSize); if (bufSize < rx_GetMinUdpBufSize()) printf ("Warning:udpsize %d is less than minimum %d; ignoring\n", bufSize, rx_GetMinUdpBufSize()); else udpBufSize = bufSize; } else if (strcmp(argv[code], "-enable_peer_stats") == 0) { rx_enablePeerRPCStats(); } else if (strcmp(argv[code], "-enable_process_stats") == 0) { rx_enableProcessRPCStats(); } else if (strcmp(argv[code], "-preserve-vol-stats") == 0) { DoPreserveVolumeStats = 1; } else if (strcmp(argv[code], "-sync") == 0) { if ((code + 1) >= argc) { printf("You have to specify -sync <sync_behavior>\n"); exit(1); } ih_PkgDefaults(); if (ih_SetSyncBehavior(argv[++code])) { printf("Invalid -sync value %s\n", argv[code]); exit(1); } } #ifndef AFS_NT40_ENV else if (strcmp(argv[code], "-syslog") == 0) { /* set syslog logging flag */ serverLogSyslog = 1; } else if (strncmp(argv[code], "-syslog=", 8) == 0) { serverLogSyslog = 1; serverLogSyslogFacility = atoi(argv[code] + 8); } #endif #ifdef AFS_PTHREAD_ENV else if (strcmp(argv[code], "-convert") == 0) convertToOsd = 1; else if (strcmp(argv[code], "-libafsosd") == 0) libafsosd = 1; #endif else { printf("volserver: unrecognized flag '%s'\n", argv[code]); usage: #ifndef AFS_NT40_ENV printf("Usage: volserver [-log] [-p <number of processes>] " "[-auditlog <log path>] [-d <debug level>] " "[-nojumbo] [-jumbo] [-rxmaxmtu <bytes>] [-rxbind] [-allow-dotted-principals] " "[-udpsize <size of socket buffer in bytes>] " "[-syslog[=FACILITY]] -mbpersleep <MB / 1 sec sleep>" "%s" "[-enable_peer_stats] [-enable_process_stats] " "[-sync <always | delayed | onclose | never>] " #ifdef AFS_PTHREAD_ENV , libafsosd ? "[-convert] ":"", #endif "[-help]\n"); #else printf("Usage: volserver [-log] [-p <number of processes>] " "[-auditlog <log path>] [-d <debug level>] " "[-nojumbo] [-jumbo] [-rxmaxmtu <bytes>] [-rxbind] [-allow-dotted-principals] " "[-udpsize <size of socket buffer in bytes>] " "[-enable_peer_stats] [-enable_process_stats] " "[-sync <always | delayed | onclose | never>] " "[-help]\n"); #endif VS_EXIT(1); } } if (auditFileName) { osi_audit_file(auditFileName); osi_audit(VS_StartEvent, 0, AUD_END); } #ifdef AFS_SGI_VNODE_GLUE if (afs_init_kernel_config(-1) < 0) { printf ("Can't determine NUMA configuration, not starting volserver.\n"); exit(1); } #endif InitErrTabs(); #ifdef AFS_PTHREAD_ENV SetLogThreadNumProgram( threadNum ); #endif #ifdef AFS_NT40_ENV if (afs_winsockInit() < 0) { ReportErrorEventAlt(AFSEVT_SVR_WINSOCK_INIT_FAILED, 0, argv[0], 0); printf("Volume server unable to start winsock, exiting.\n"); exit(1); } #endif /* Open VolserLog and map stdout, stderr into it; VInitVolumePackage2 can log, so we need to do this here */ OpenLog(AFSDIR_SERVER_VOLSERLOG_FILEPATH); VOptDefaults(volumeServer, &opts); #ifdef AFS_PTHREAD_ENV if (libafsosd) { extern struct vol_data_v0 vol_data_v0; extern struct volser_data_v0 volser_data_v0; struct init_volser_inputs input = { &vol_data_v0, &volser_data_v0 }; struct init_volser_outputs output = { &osdvol, &osdvolser }; code = load_libafsosd("init_volser_afsosd", &input, &output); if (code) { ViceLog(0, ("Loading libafsosd.so failed with code %d, aborting\n", code)); return -1; } } #endif if (VInitVolumePackage2(volumeServer, &opts)) { Log("Shutting down: errors encountered initializing volume package\n"); exit(1); } /* For nuke() */ Lock_Init(&localLock); DInit(40); #ifndef AFS_PTHREAD_ENV vol_PollProc = IOMGR_Poll; /* tell vol pkg to poll io system periodically */ #endif #ifndef AFS_NT40_ENV rxi_syscallp = volser_syscall; #endif rx_nPackets = rxpackets; /* set the max number of packets */ if (udpBufSize) rx_SetUdpBufSize(udpBufSize); /* set the UDP buffer size for receive */ if (rxBind) { afs_int32 ccode; if (AFSDIR_SERVER_NETRESTRICT_FILEPATH || AFSDIR_SERVER_NETINFO_FILEPATH) { char reason[1024]; ccode = parseNetFiles(SHostAddrs, NULL, NULL, ADDRSPERSITE, reason, AFSDIR_SERVER_NETINFO_FILEPATH, AFSDIR_SERVER_NETRESTRICT_FILEPATH); } else { ccode = rx_getAllAddr(SHostAddrs, ADDRSPERSITE); } if (ccode == 1) host = SHostAddrs[0]; } code = rx_InitHost(host, (int)htons(AFSCONF_VOLUMEPORT)); if (code) { fprintf(stderr, "rx init failed on socket AFSCONF_VOLUMEPORT %u\n", AFSCONF_VOLUMEPORT); VS_EXIT(1); } if (!rxJumbograms) { /* Don't allow 3.4 vos clients to send jumbograms and we don't send. */ rx_SetNoJumbo(); } if (rxMaxMTU != -1) { rx_SetMaxMTU(rxMaxMTU); } rx_GetIFInfo(); #ifndef AFS_PTHREAD_ENV rx_SetRxDeadTime(420); #endif memset(busyFlags, 0, sizeof(busyFlags)); SetupLogSignals(); { #ifdef AFS_PTHREAD_ENV pthread_t tid; pthread_attr_t tattr; osi_Assert(pthread_attr_init(&tattr) == 0); osi_Assert(pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED) == 0); osi_Assert(pthread_create(&tid, &tattr, BKGLoop, NULL) == 0); #else PROCESS pid; LWP_CreateProcess(BKGLoop, 16*1024, 3, 0, "vol bkg daemon", &pid); LWP_CreateProcess(BKGSleep,16*1024, 3, 0, "vol slp daemon", &pid); #endif } /* Create a single security object, in this case the null security object, for unauthenticated connections, which will be used to control security on connections made to this server */ tdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH); if (!tdir) { Abort("volser: could not open conf files in %s\n", AFSDIR_SERVER_ETC_DIRPATH); VS_EXIT(1); } afsconf_GetKey(tdir, 999, &tkey); afsconf_BuildServerSecurityObjects(tdir, 0, &securityClasses, &numClasses); if (securityClasses[0] == NULL) Abort("rxnull_NewServerSecurityObject"); service = rx_NewServiceHost(host, 0, VOLSERVICE_ID, "VOLSER", securityClasses, numClasses, AFSVolExecuteRequest); if (service == (struct rx_service *)0) Abort("rx_NewService"); rx_SetBeforeProc(service, MyBeforeProc); rx_SetAfterProc(service, MyAfterProc); rx_SetIdleDeadTime(service, 0); /* never timeout */ if (lwps < 4) lwps = 4; rx_SetMaxProcs(service, lwps); #if defined(AFS_XBSD_ENV) rx_SetStackSize(service, (128 * 1024)); #elif defined(AFS_SGI_ENV) rx_SetStackSize(service, (48 * 1024)); #else rx_SetStackSize(service, (32 * 1024)); #endif if (rxkadDisableDotCheck) { rx_SetSecurityConfiguration(service, RXS_CONFIG_FLAGS, (void *)RXS_CONFIG_FLAGS_DISABLE_DOTCHECK); } service = rx_NewService(0, RX_STATS_SERVICE_ID, "rpcstats", securityClasses, numClasses, RXSTATS_ExecuteRequest); if (service == (struct rx_service *)0) Abort("rx_NewService"); rx_SetMinProcs(service, 2); rx_SetMaxProcs(service, 4); #ifdef AFS_PTHREAD_ENV if (libafsosd) { service = rx_NewService(0, 7, "afsosd", securityClasses, numClasses, (osdvolser->op_AFSVOLOSD_ExecuteRequest)); if (!service) { ViceLog(0, ("Failed to initialize afsosd rpc service.\n")); exit(-1); } rx_SetBeforeProc(service, MyBeforeProc); rx_SetAfterProc(service, MyAfterProc); rx_SetIdleDeadTime(service, 0); /* never timeout */ rx_SetMinProcs(service, 2); if (lwps < 4) lwps = 4; rx_SetMaxProcs(service, lwps); #if defined(AFS_XBSD_ENV) rx_SetStackSize(service, (128 * 1024)); #elif defined(AFS_SGI_ENV) rx_SetStackSize(service, (48 * 1024)); #else rx_SetStackSize(service, (32 * 1024)); #endif } #endif /* AFS_PTHREAD_ENV */ LogCommandLine(argc, argv, "Volserver", VolserVersion, "Starting AFS", Log); FT_GetTimeOfDay(&statisticStart, 0); if (afsconf_GetLatestKey(tdir, NULL, NULL) == 0) { LogDesWarning(); } if (TTsleep) { Log("Will sleep %d second%s every %d second%s\n", TTsleep, (TTsleep > 1) ? "s" : "", TTrun + TTsleep, (TTrun + TTsleep > 1) ? "s" : ""); } /* allow super users to manage RX statistics */ /* allow super users to manage RX statistics */ rx_SetRxStatUserOk(vol_rxstat_userok); rx_StartServer(1); /* Donate this process to the server process pool */ osi_audit(VS_FinishEvent, (-1), AUD_END); Abort("StartServer returned?"); return 0; /* not reached */ }
/* bnode lwp executes this code repeatedly */ static void * bproc(void *unused) { afs_int32 code; struct bnode *tb; afs_int32 temp; struct bnode_proc *tp; struct bnode *nb; int options; /* must not be register */ struct timeval tv; int setAny; int status; while (1) { /* first figure out how long to sleep for */ temp = 0x7fffffff; /* afs_int32 time; maxint doesn't work in select */ setAny = 0; for (tb = allBnodes; tb; tb = tb->next) { if (tb->flags & BNODE_NEEDTIMEOUT) { if (tb->nextTimeout < temp) { setAny = 1; temp = tb->nextTimeout; } } } /* now temp has the time at which we should wakeup next */ /* sleep */ if (setAny) temp -= FT_ApproxTime(); /* how many seconds until next event */ else temp = 999999; if (temp > 0) { tv.tv_sec = temp; tv.tv_usec = 0; code = IOMGR_Select(0, 0, 0, 0, &tv); } else code = 0; /* fake timeout code */ /* figure out why we woke up; child exit or timeouts */ FT_GetTimeOfDay(&tv, 0); /* must do the real gettimeofday once and a while */ temp = tv.tv_sec; /* check all bnodes to see which ones need timeout events */ for (tb = allBnodes; tb; tb = nb) { if ((tb->flags & BNODE_NEEDTIMEOUT) && temp > tb->nextTimeout) { bnode_Hold(tb); BOP_TIMEOUT(tb); bnode_Check(tb); if (tb->flags & BNODE_NEEDTIMEOUT) { /* check again, BOP_TIMEOUT could change */ tb->nextTimeout = FT_ApproxTime() + tb->period; } nb = tb->next; bnode_Release(tb); /* delete may occur here */ } else nb = tb->next; } if (code < 0) { /* signalled, probably by incoming signal */ while (1) { options = WNOHANG; bnode_waiting = options | 0x800000; code = waitpid((pid_t) - 1, &status, options); bnode_waiting = 0; if (code == 0 || code == -1) break; /* all done */ /* otherwise code has a process id, which we now search for */ for (tp = allProcs; tp; tp = tp->next) if (tp->pid == code) break; if (tp) { /* found the pid */ tb = tp->bnode; bnode_Hold(tb); /* count restarts in last 10 seconds */ if (temp > tb->rsTime + 30) { /* it's been 10 seconds we've been counting */ tb->rsTime = temp; tb->rsCount = 0; } if (WIFSIGNALED(status) == 0) { /* exited, not signalled */ tp->lastExit = WEXITSTATUS(status); tp->lastSignal = 0; if (tp->lastExit) { tb->errorCode = tp->lastExit; tb->lastErrorExit = FT_ApproxTime(); RememberProcName(tp); tb->errorSignal = 0; } if (tp->coreName) bozo_Log("%s:%s exited with code %d\n", tb->name, tp->coreName, tp->lastExit); else bozo_Log("%s exited with code %d\n", tb->name, tp->lastExit); } else { /* Signal occurred, perhaps spurious due to shutdown request. * If due to a shutdown request, don't overwrite last error * information. */ tp->lastSignal = WTERMSIG(status); tp->lastExit = 0; if (tp->lastSignal != SIGQUIT && tp->lastSignal != SIGTERM && tp->lastSignal != SIGKILL) { tb->errorSignal = tp->lastSignal; tb->lastErrorExit = FT_ApproxTime(); RememberProcName(tp); } if (tp->coreName) bozo_Log("%s:%s exited on signal %d%s\n", tb->name, tp->coreName, tp->lastSignal, WCOREDUMP(status) ? " (core dumped)" : ""); else bozo_Log("%s exited on signal %d%s\n", tb->name, tp->lastSignal, WCOREDUMP(status) ? " (core dumped)" : ""); SaveCore(tb, tp); } tb->lastAnyExit = FT_ApproxTime(); if (tb->notifier) { bozo_Log("BNODE: Notifier %s will be called\n", tb->notifier); hdl_notifier(tp); } BOP_PROCEXIT(tb, tp); bnode_Check(tb); if (tb->rsCount++ > 10) { /* 10 in 10 seconds */ tb->flags |= BNODE_ERRORSTOP; bnode_SetGoal(tb, BSTAT_SHUTDOWN); bozo_Log ("BNODE '%s' repeatedly failed to start, perhaps missing executable.\n", tb->name); } bnode_Release(tb); /* bnode delete can happen here */ DeleteProc(tp); } else bnode_stats.weirdPids++; } } } return NULL; }
/* save core file, if any */ static void SaveCore(struct bnode *abnode, struct bnode_proc *aproc) { char tbuffer[256]; struct stat tstat; afs_int32 code = 0; char *corefile = NULL; #ifdef BOZO_SAVE_CORES struct timeval Start; struct tm *TimeFields; char FileName[256]; #endif /* Linux always appends the PID to core dumps from threaded processes, so * we have to scan the directory to find core files under another name. */ if (DoCore) { strcpy(tbuffer, DoCore); strcat(tbuffer, "/"); strcat(tbuffer, AFSDIR_CORE_FILE); } else code = stat(AFSDIR_SERVER_CORELOG_FILEPATH, &tstat); if (code) { DIR *logdir; struct dirent *file; size_t length; unsigned long pid; const char *coredir = AFSDIR_LOGS_DIR; if (DoCore) coredir = DoCore; logdir = opendir(coredir); if (logdir == NULL) return; while ((file = readdir(logdir)) != NULL) { if (strncmp(file->d_name, "core.", 5) != 0) continue; pid = atol(file->d_name + 5); if (pid == aproc->pid) { length = strlen(coredir) + strlen(file->d_name) + 2; corefile = malloc(length); if (corefile == NULL) { closedir(logdir); return; } snprintf(corefile, length, "%s/%s", coredir, file->d_name); code = 0; break; } } closedir(logdir); } else { corefile = strdup(tbuffer); } if (code) return; bnode_CoreName(abnode, aproc->coreName, tbuffer); #ifdef BOZO_SAVE_CORES FT_GetTimeOfDay(&Start, 0); TimeFields = localtime(&Start.tv_sec); sprintf(FileName, "%s.%d%02d%02d%02d%02d%02d", tbuffer, TimeFields->tm_year + 1900, TimeFields->tm_mon + 1, TimeFields->tm_mday, TimeFields->tm_hour, TimeFields->tm_min, TimeFields->tm_sec); strcpy(tbuffer, FileName); #endif code = renamefile(corefile, tbuffer); free(corefile); }
static void *IOMGR(void *dummy) { for (;;) { int code; struct TM_Elem *earliest; struct timeval timeout, junk; bool woke_someone; FD_ZERO(&IOMGR_readfds); FD_ZERO(&IOMGR_writefds); FD_ZERO(&IOMGR_exceptfds); IOMGR_nfds = 0; /* Wake up anyone who has expired or who has received a Unix signal between executions. Keep going until we run out. */ do { woke_someone = FALSE; /* Wake up anyone waiting on signals. */ /* Note: SignalSignals() may yield! */ if (anySigsDelivered && SignalSignals ()) woke_someone = TRUE; FT_GetTimeOfDay(&junk, 0); /* force accurate time check */ TM_Rescan(Requests); for (;;) { struct IoRequest *req; struct TM_Elem *expired; expired = TM_GetExpired(Requests); if (expired == NULL) break; woke_someone = TRUE; req = (struct IoRequest *) expired -> BackPointer; #ifdef DEBUG if (lwp_debug != 0) puts("[Polling SELECT]"); #endif /* DEBUG */ /* no data ready */ if (req->readfds) FD_N_ZERO(req->nfds, req->readfds); if (req->writefds) FD_N_ZERO(req->nfds, req->writefds); if (req->exceptfds) FD_N_ZERO(req->nfds, req->exceptfds); req->nfds = 0; req->result = 0; /* no fds ready */ TM_Remove(Requests, &req->timeout); #ifdef DEBUG req -> timeout.Next = (struct TM_Elem *) 2; req -> timeout.Prev = (struct TM_Elem *) 2; #endif /* DEBUG */ LWP_QSignal(req->pid); req->pid->iomgrRequest = 0; } if (woke_someone) LWP_DispatchProcess(); } while (woke_someone); /* Collect requests & update times */ FD_ZERO(&IOMGR_readfds); FD_ZERO(&IOMGR_writefds); FD_ZERO(&IOMGR_exceptfds); IOMGR_nfds = 0; FOR_ALL_ELTS(r, Requests, { struct IoRequest *req; req = (struct IoRequest *) r -> BackPointer; FDSetSet(req->nfds, &IOMGR_readfds, req->readfds); FDSetSet(req->nfds, &IOMGR_writefds, req->writefds); FDSetSet(req->nfds, &IOMGR_exceptfds, req->exceptfds); if (req->nfds > IOMGR_nfds) IOMGR_nfds = req->nfds; }) earliest = TM_GetEarliest(Requests); if (earliest != NULL) { timeout = earliest -> TimeLeft; /* Do select */ #ifdef DEBUG if (lwp_debug != 0) { #ifdef AFS_NT40_ENV int idbg; printf("[Read Select:"); if (IOMGR_readfds.fd_count == 0) printf(" none]\n"); else { for (idbg=0; idbg<IOMGR_readfds.fd_count; idbg++) printf(" %d", IOMGR_readfds.fd_array[idbg]); printf("]\n"); } printf("[Write Select:"); if (IOMGR_writefds.fd_count == 0) printf(" none]\n"); else { for (idbg=0; idbg<IOMGR_writefds.fd_count; idbg++) printf(" %d", IOMGR_writefds.fd_array[idbg]); printf("]\n"); } printf("[Except Select:"); if (IOMGR_exceptfds.fd_count == 0) printf(" none]\n"); else { for (idbg=0; idbg<IOMGR_exceptfds.fd_count; idbg++) printf(" %d", IOMGR_exceptfds.fd_array[idbg]); printf("]\n"); } #else /* Only prints first 32. */ printf("[select(%d, 0x%x, 0x%x, 0x%x, ", IOMGR_nfds, *(int*)&IOMGR_readfds, *(int*)&IOMGR_writefds, *(int*)&IOMGR_exceptfds); #endif /* AFS_NT40_ENV */ if (timeout.tv_sec == -1 && timeout.tv_usec == -1) puts("INFINITE)]"); else printf("<%d, %d>)]\n", timeout.tv_sec, timeout.tv_usec); } #endif /* DEBUG */ iomgr_timeout = timeout; if (timeout.tv_sec == -1 && timeout.tv_usec == -1) { /* infinite, sort of */ iomgr_timeout.tv_sec = 100000000; iomgr_timeout.tv_usec = 0; } #if defined(AFS_NT40_ENV) || defined(AFS_LINUX24_ENV) /* On NT, signals don't interrupt a select call. So this can potentially * lead to long wait times before a signal is honored. To avoid this we * dont do select() for longer than IOMGR_MAXWAITTIME (5 secs) */ /* Whereas Linux seems to sometimes "lose" signals */ if (iomgr_timeout.tv_sec > (IOMGR_MAXWAITTIME - 1)) { iomgr_timeout.tv_sec = IOMGR_MAXWAITTIME; iomgr_timeout.tv_usec = 0; } #endif /* NT40 */ /* Check one last time for a signal delivery. If one comes after this, the signal handler will set iomgr_timeout to zero, causing the select to return immediately. The timer package won't return a zero timeval because all of those guys were handled above. I'm assuming that the kernel masks signals while it's picking up the parameters to select. This may a bad assumption. -DN */ if (anySigsDelivered) continue; /* go to the top and handle them. */ #ifdef AFS_NT40_ENV if (IOMGR_readfds.fd_count == 0 && IOMGR_writefds.fd_count == 0 && IOMGR_exceptfds.fd_count == 0) { DWORD stime; code = 0; if (iomgr_timeout.tv_sec || iomgr_timeout.tv_usec) { stime = iomgr_timeout.tv_sec * 1000 + iomgr_timeout.tv_usec/1000; if (!stime) stime = 1; Sleep(stime); } } else #endif { /* select runs much faster if 0's are passed instead of &0s */ code = select(IOMGR_nfds, (FDSetEmpty(IOMGR_nfds, &IOMGR_readfds)) ? (fd_set*)0 : &IOMGR_readfds, (FDSetEmpty(IOMGR_nfds, &IOMGR_writefds)) ? (fd_set*)0 : &IOMGR_writefds, (FDSetEmpty(IOMGR_nfds, &IOMGR_exceptfds)) ? (fd_set*)0 : &IOMGR_exceptfds, &iomgr_timeout); } if (code < 0) { int e=1; #if defined(AFS_SUN_ENV) /* Tape drives on Sun boxes do not support select and return ENXIO */ if (errno == ENXIO) e=0, code=1; #endif #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_AIX32_ENV) /* For SGI and SVR4 - poll & select can return EAGAIN ... */ if (errno == EAGAIN) e=0; #endif #if defined(AFS_SUN5_ENV) /* On sun4x_55, select doesn't block signal. It could be interupted by a signal that changes iomgr_timeout, and then select returns with EINVAL. In this case, we need to retry. */ if (errno==EINVAL && anySigsDelivered) e = 0; #endif /* AFS_SUN5_ENV */ if ((errno != EINTR) && e) { #ifndef AFS_NT40_ENV int i; for(i=0; i<FD_SETSIZE; i++) { if (fcntl(i, F_GETFD, 0) < 0 && errno == EBADF) FD_SET(i, &openMask); } #endif iomgr_errno = errno; opr_abort(); } } /* See what happened */ if (code > 0) { /* Action -- wake up everyone involved */ SignalIO(IOMGR_nfds, &IOMGR_readfds, &IOMGR_writefds, &IOMGR_exceptfds, code); } else if (code == 0 && (iomgr_timeout.tv_sec != 0 || iomgr_timeout.tv_usec != 0)) { /* Real timeout only if signal handler hasn't set iomgr_timeout to zero. */ #if defined(AFS_NT40_ENV) || defined(AFS_LINUX24_ENV) /* On NT, real timeout only if above and if iomgr_timeout * interval is equal to timeout interval (i.e., not adjusted * to check for pseudo-signals). */ /* And also for Linux as above */ if (iomgr_timeout.tv_sec != timeout.tv_sec || iomgr_timeout.tv_usec != timeout.tv_usec) { /* signal check interval timed out; not real timeout */ continue; } #endif /* AFS_NT40_ENV */ FT_GetTimeOfDay(&junk, 0); SignalTimeout(code, &timeout); } } LWP_DispatchProcess(); }