/** * Signal handler for HUP which tells us to swap the log file * and reload configuration file if specified * * @param sig */ void do_signal_sighup(RunTimeOpts * rtOpts, PtpClock * ptpClock) { NOTIFY("SIGHUP received\n"); #ifdef RUNTIME_DEBUG if(rtOpts->transport == UDP_IPV4 && rtOpts->ipMode != IPMODE_UNICAST) { DBG("SIGHUP - running an ipv4 multicast based mode, re-sending IGMP joins\n"); netRefreshIGMP(&ptpClock->netPath, rtOpts, ptpClock); } #endif /* RUNTIME_DEBUG */ /* if we don't have a config file specified, we're done - just reopen log files*/ if(strlen(rtOpts->configFile) != 0) { dictionary* tmpConfig = dictionary_new(0); /* Try reloading the config file */ NOTIFY("Reloading configuration file: %s\n",rtOpts->configFile); if(!loadConfigFile(&tmpConfig, rtOpts)) { dictionary_del(&tmpConfig); } else { dictionary_merge(rtOpts->cliConfig, tmpConfig, 1, 1, "from command line"); applyConfig(tmpConfig, rtOpts, ptpClock); dictionary_del(&tmpConfig); } } /* tell the service it can perform any HUP-triggered actions */ ptpClock->timingService.reloadRequested = TRUE; if(rtOpts->recordLog.logEnabled || rtOpts->eventLog.logEnabled || (rtOpts->statisticsLog.logEnabled)) INFO("Reopening log files\n"); restartLogging(rtOpts); if(rtOpts->statisticsLog.logEnabled) ptpClock->resetStatisticsLog = TRUE; }
/* perform actions required when leaving 'port_state' and entering 'state' */ void toState(UInteger8 state, RunTimeOpts *rtOpts, PtpClock *ptpClock) { ptpClock->message_activity = TRUE; /* leaving state tasks */ switch (ptpClock->portState) { case PTP_MASTER: timerStop(SYNC_INTERVAL_TIMER, ptpClock->itimer); timerStop(ANNOUNCE_INTERVAL_TIMER, ptpClock->itimer); timerStop(PDELAYREQ_INTERVAL_TIMER, ptpClock->itimer); break; case PTP_SLAVE: timerStop(ANNOUNCE_RECEIPT_TIMER, ptpClock->itimer); if (ptpClock->delayMechanism == E2E) timerStop(DELAYREQ_INTERVAL_TIMER, ptpClock->itimer); else if (ptpClock->delayMechanism == P2P) timerStop(PDELAYREQ_INTERVAL_TIMER, ptpClock->itimer); initClock(rtOpts, ptpClock); break; case PTP_PASSIVE: timerStop(PDELAYREQ_INTERVAL_TIMER, ptpClock->itimer); timerStop(ANNOUNCE_RECEIPT_TIMER, ptpClock->itimer); break; case PTP_LISTENING: timerStop(ANNOUNCE_RECEIPT_TIMER, ptpClock->itimer); break; default: break; } /* entering state tasks */ /* * No need of PRE_MASTER state because of only ordinary clock * implementation. */ switch (state) { case PTP_INITIALIZING: DBG("state PTP_INITIALIZING\n"); ptpClock->portState = PTP_INITIALIZING; break; case PTP_FAULTY: DBG("state PTP_FAULTY\n"); ptpClock->portState = PTP_FAULTY; break; case PTP_DISABLED: DBG("state PTP_DISABLED\n"); ptpClock->portState = PTP_DISABLED; break; case PTP_LISTENING: /* in Listening mode, make sure we don't send anything. Instead we just expect/wait for announces (started below) */ timerStop(SYNC_INTERVAL_TIMER, ptpClock->itimer); timerStop(ANNOUNCE_INTERVAL_TIMER, ptpClock->itimer); timerStop(PDELAYREQ_INTERVAL_TIMER, ptpClock->itimer); timerStop(DELAYREQ_INTERVAL_TIMER, ptpClock->itimer); /* * Count how many _unique_ timeouts happen to us. * If we were already in Listen mode, then do not count this as a seperate reset, but stil do a new IGMP refresh */ if (ptpClock->portState != PTP_LISTENING) { ptpClock->reset_count++; } /* Revert to the original DelayReq interval, and ignore the one for the last master */ ptpClock->logMinDelayReqInterval = rtOpts->initial_delayreq; /* force a IGMP refresh per reset */ if (rtOpts->do_IGMP_refresh) { netRefreshIGMP(&ptpClock->netPath, rtOpts, ptpClock); } DBG("state PTP_LISTENING\n"); INFO(" now in state PTP_LISTENING\n"); timerStart(ANNOUNCE_RECEIPT_TIMER, (ptpClock->announceReceiptTimeout) * (pow(2,ptpClock->logAnnounceInterval)), ptpClock->itimer); ptpClock->portState = PTP_LISTENING; break; case PTP_MASTER: DBG("state PTP_MASTER\n"); INFO(" now in state PTP_MASTER\n"); timerStart(SYNC_INTERVAL_TIMER, pow(2,ptpClock->logSyncInterval), ptpClock->itimer); DBG("SYNC INTERVAL TIMER : %f \n", pow(2,ptpClock->logSyncInterval)); timerStart(ANNOUNCE_INTERVAL_TIMER, pow(2,ptpClock->logAnnounceInterval), ptpClock->itimer); timerStart(PDELAYREQ_INTERVAL_TIMER, pow(2,ptpClock->logMinPdelayReqInterval), ptpClock->itimer); ptpClock->portState = PTP_MASTER; break; case PTP_PASSIVE: DBG("state PTP_PASSIVE\n"); INFO(" now in state PTP_PASSIVE\n"); timerStart(PDELAYREQ_INTERVAL_TIMER, pow(2,ptpClock->logMinPdelayReqInterval), ptpClock->itimer); timerStart(ANNOUNCE_RECEIPT_TIMER, (ptpClock->announceReceiptTimeout) * (pow(2,ptpClock->logAnnounceInterval)), ptpClock->itimer); ptpClock->portState = PTP_PASSIVE; p1(ptpClock, rtOpts); break; case PTP_UNCALIBRATED: DBG("state PTP_UNCALIBRATED\n"); ptpClock->portState = PTP_UNCALIBRATED; break; case PTP_SLAVE: DBG("state PTP_SLAVE\n"); INFO(" now in state PTP_SLAVE\n"); initClock(rtOpts, ptpClock); ptpClock->waitingForFollow = FALSE; ptpClock->waitingForDelayResp = FALSE; // FIXME: clear these vars inside initclock clearTime(&ptpClock->pdelay_req_send_time); clearTime(&ptpClock->pdelay_req_receive_time); clearTime(&ptpClock->pdelay_resp_send_time); clearTime(&ptpClock->pdelay_resp_receive_time); timerStart(OPERATOR_MESSAGES_TIMER, OPERATOR_MESSAGES_INTERVAL, ptpClock->itimer); timerStart(ANNOUNCE_RECEIPT_TIMER, (ptpClock->announceReceiptTimeout) * (pow(2,ptpClock->logAnnounceInterval)), ptpClock->itimer); /* * Previously, this state transition would start the delayreq timer immediately. * However, if this was faster than the first received sync, then the servo would drop the delayResp * Now, we only start the timer after we receive the first sync (in handle_sync()) */ ptpClock->waiting_for_first_sync = TRUE; ptpClock->waiting_for_first_delayresp = TRUE; ptpClock->portState = PTP_SLAVE; break; default: DBG("to unrecognized state\n"); break; } if (rtOpts->displayStats) displayStats(rtOpts, ptpClock); }
/** * Signal handler for HUP which tells us to swap the log file * and reload configuration file if specified * * @param sig */ void do_signal_sighup(RunTimeOpts * rtOpts, PtpClock * ptpClock) { NOTIFY("SIGHUP received\n"); #ifdef RUNTIME_DEBUG if(rtOpts->transport == UDP_IPV4 && rtOpts->ip_mode != IPMODE_UNICAST) { DBG("SIGHUP - running an ipv4 multicast based mode, re-sending IGMP joins\n"); netRefreshIGMP(&ptpClock->netPath, rtOpts, ptpClock); } #endif /* RUNTIME_DEBUG */ /* if we don't have a config file specified, we're done - just reopen log files*/ if(strlen(rtOpts->configFile) == 0) goto end; dictionary* tmpConfig = dictionary_new(0); /* Try reloading the config file */ NOTIFY("Reloading configuration file: %s\n",rtOpts->configFile); if(!loadConfigFile(&tmpConfig, rtOpts)) { dictionary_del(tmpConfig); goto end; } dictionary_merge(rtOpts->cliConfig, tmpConfig, 1, "from command line"); /* Load default config to fill in the blanks in the config file */ RunTimeOpts tmpOpts; loadDefaultSettings(&tmpOpts); /* Check the new configuration for errors, fill in the blanks from defaults */ if( ( rtOpts->candidateConfig = parseConfig(tmpConfig,&tmpOpts)) == NULL ) { WARNING("Configuration file has errors, reload aborted\n"); dictionary_del(tmpConfig); goto end; } /* Check for changes between old and new configuration */ if(compareConfig(rtOpts->candidateConfig,rtOpts->currentConfig)) { INFO("Configuration unchanged\n"); goto cleanup; } /* * Mark which subsystems have to be restarted. Most of this will be picked up by doState() * If there are errors past config correctness (such as non-existent NIC, * or lock file clashes if automatic lock files used - abort the mission */ rtOpts->restartSubsystems = checkSubsystemRestart(rtOpts->candidateConfig, rtOpts->currentConfig); /* If we're told to re-check lock files, do it: tmpOpts already has what rtOpts should */ if( (rtOpts->restartSubsystems & PTPD_CHECK_LOCKS) && tmpOpts.autoLockFile && !checkOtherLocks(&tmpOpts)) { rtOpts->restartSubsystems = -1; } /* If the network configuration has changed, check if the interface is OK */ if(rtOpts->restartSubsystems & PTPD_RESTART_NETWORK) { INFO("Network configuration changed - checking interface\n"); if(!testInterface(tmpOpts.ifaceName, &tmpOpts)) { rtOpts->restartSubsystems = -1; ERROR("Error: Cannot use %s interface\n",tmpOpts.ifaceName); } } #if defined(linux) && defined(HAVE_SCHED_H) /* Changing the CPU affinity mask */ if(rtOpts->restartSubsystems & PTPD_CHANGE_CPUAFFINITY) { NOTIFY("Applying CPU binding configuration: changing selected CPU core\n"); cpu_set_t mask; CPU_ZERO(&mask); if(tmpOpts.cpuNumber > -1) { CPU_SET(tmpOpts.cpuNumber,&mask); } else { int i; for(i = 0; i < CPU_SETSIZE; i++) { CPU_SET(i, &mask); } } if(sched_setaffinity(0, sizeof(mask), &mask) < 0) { if(tmpOpts.cpuNumber == -1) { PERROR("Could not unbind from CPU core %d", rtOpts->cpuNumber); } else { PERROR("Could bind to CPU core %d", tmpOpts.cpuNumber); } rtOpts->restartSubsystems = -1; } else { if(tmpOpts.cpuNumber > -1) INFO("Successfully bound "PTPD_PROGNAME" to CPU core %d\n", tmpOpts.cpuNumber); else INFO("Successfully unbound "PTPD_PROGNAME" from cpu core CPU core %d\n", rtOpts->cpuNumber); } } #endif /* linux && HAVE_SCHED_H */ #ifdef HAVE_SYS_CPUSET_H /* Changing the CPU affinity mask */ if (rtOpts->restartSubsystems & PTPD_CHANGE_CPUAFFINITY) { NOTIFY("Applying CPU binding configuration:" "changing selected CPU core\n"); cpuset_t mask; CPU_ZERO(&mask); if (tmpOpts.cpuNumber < 0) { if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_CPUSET, 1, sizeof(mask), &mask) < 0) PERROR("Could not get affinity."); if (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(mask), &mask) < 0) PERROR("Could not unbind from CPU core %d", rtOpts->cpuNumber); else INFO("Successfully unbound " PTPD_PROGNAME" from cpu core CPU core %d\n", rtOpts->cpuNumber); } else { CPU_SET(tmpOpts.cpuNumber,&mask); if (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(mask), &mask) < 0) { PERROR("Could not bind to CPU core %d", tmpOpts.cpuNumber); rtOpts->restartSubsystems = -1; } else { INFO("Successfully bound " PTPD_PROGNAME" to CPU core %d\n", tmpOpts.cpuNumber); } } } #endif if(rtOpts->restartSubsystems == -1) { ERROR("New configuration cannot be applied - aborting reload\n"); rtOpts->restartSubsystems = 0; goto cleanup; } /* Tell parseConfig to shut up - it's had its chance already */ dictionary_set(rtOpts->candidateConfig,"%quiet%:%quiet%","Y"); /** * Commit changes to rtOpts and currentConfig * (this should never fail as the config has already been checked if we're here) * However if this DOES fail, some default has been specified out of range - * this is the only situation where parse will succeed but commit not: * disable quiet mode to show what went wrong, then die. */ if (rtOpts->currentConfig) { dictionary_del(rtOpts->currentConfig); } if ( (rtOpts->currentConfig = parseConfig(rtOpts->candidateConfig,rtOpts)) == NULL) { CRITICAL("************ "PTPD_PROGNAME": parseConfig returned NULL during config commit" " - this is a BUG - report the following: \n"); dictionary_unset(rtOpts->candidateConfig,"%quiet%:%quiet%"); if ((rtOpts->currentConfig = parseConfig(rtOpts->candidateConfig,rtOpts)) == NULL) CRITICAL("*****************" PTPD_PROGNAME" shutting down **********************\n"); /* * Could be assert(), but this should be done any time this happens regardless of * compile options. Anyhow, if we're here, the daemon will no doubt segfault soon anyway */ abort(); } /* clean up */ cleanup: dictionary_del(tmpConfig); dictionary_del(rtOpts->candidateConfig); end: if(rtOpts->recordLog.logEnabled || rtOpts->eventLog.logEnabled || (rtOpts->statisticsLog.logEnabled)) INFO("Reopening log files\n"); restartLogging(rtOpts); if(rtOpts->statisticsLog.logEnabled) ptpClock->resetStatisticsLog = TRUE; }