/** * \brief Forks a separate simple sleep() -&- sync periodic timer * * Forks a very basic periodic timer process, that just sleep()s for * the specified interval and then calls the timer function. * The new "sync timer" process execution start immediately, the sleep() * is called first (so the first call to the timer function will happen * \<interval\> seconds after the call to fork_sync_timer) * @param child_id @see fork_process() * @param desc @see fork_process() * @param make_sock @see fork_process() * @param f timer function/callback * @param param parameter passed to the timer function * @param interval interval in seconds. * @return pid of the new process on success, -1 on error * (doesn't return anything in the child process) */ int fork_sync_timer(int child_id, char* desc, int make_sock, timer_function* f, void* param, int interval) { int pid; ticks_t ts1 = 0; ticks_t ts2 = 0; pid=fork_process(child_id, desc, make_sock); if (pid<0) return -1; if (pid==0){ /* child */ interval *= 1000; /* miliseconds */ ts2 = interval; if (cfg_child_init()) return -1; for(;;){ if (ts2>interval) sleep_us(1000); /* 1 milisecond sleep to catch up */ else sleep_us(ts2*1000); /* microseconds sleep */ ts1 = get_ticks_raw(); cfg_update(); f(TICKS_TO_S(ts1), param); /* ticks in sec for compatibility with old timers */ /* adjust the next sleep duration */ ts2 = interval - TICKS_TO_MS(get_ticks_raw()) + TICKS_TO_MS(ts1); } } /* parent */ return pid; }
u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) { #define SYS_MSPERTICK (SYSTMR_INTERVAL/SYSTMR_CLK_FREQ_KHZ) #define TICKS_TO_MS(x) ((x) * SYS_MSPERTICK) if (timeout) { /* Try to acquire the semaphore within timeout. If not return */ u32_t ticks = xget_clock_ticks(); u32_t nticks = 0; if (!sem_timedwait(sem, timeout)) { /* sem_timedwait returns 0 on success */ nticks = xget_clock_ticks(); if (nticks >= ticks) return TICKS_TO_MS(nticks-ticks); else { /* overflow condition */ /* we'll assume that this has overflowed just once */ return TICKS_TO_MS((0xffffffff - ticks) + nticks); } } else { return SYS_ARCH_TIMEOUT; } } else { sem_wait(sem); } return 0; }
/* frees all the expired entries until either there are no more of them * or the total memory used is <= target (to free all of them use -1 for * targer) * params: target - free expired entries until no more then taget memory * is used (use 0 to free all of them) * delta - consider an entry expired if it expires after delta * ticks from now * timeout - exit after timeout ticks * * returns: number of deleted entries * This function should be called periodically from a timer */ inline static int dst_blacklist_clean_expired(unsigned int target, ticks_t delta, ticks_t timeout) { static unsigned int start=0; unsigned int h; struct dst_blst_entry** crt; struct dst_blst_entry** tmp; struct dst_blst_entry* e; ticks_t start_time; ticks_t now; int no=0; int i; now=start_time=get_ticks_raw(); for(h=start; h!=(start+DST_BLST_HASH_SIZE); h++){ i=h%DST_BLST_HASH_SIZE; if (dst_blst_hash[i].first){ LOCK_BLST(i); for (crt=&dst_blst_hash[i].first, tmp=&(*crt)->next; *crt; crt=tmp, tmp=&(*crt)->next){ e=*crt; prefetch_loc_r((*crt)->next, 1); if ((s_ticks_t)(now+delta-(*crt)->expire)>=0){ *crt=(*crt)->next; tmp=crt; *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e); blst_destroy_entry(e); BLST_HASH_STATS_DEC(i); no++; if (*blst_mem_used<=target){ UNLOCK_BLST(i); goto skip; } } } UNLOCK_BLST(i); /* check for timeout only "between" hash cells */ now=get_ticks_raw(); if ((now-start_time)>=timeout){ DBG("_dst_blacklist_clean_expired_unsafe: timeout: %d > %d\n", TICKS_TO_MS(now-start_time), TICKS_TO_MS(timeout)); goto skip; } } } skip: start=h; /* next time we start where we left */ if (no){ DBG("dst_blacklist_clean_expired, %d entries removed\n", no); } return no; }
u32_t sys_jiffies( void ) { portTickType xTicks = xTaskGetTickCount( ); return ( u32_t )TICKS_TO_MS( xTicks ); }
/* * Blocks the thread while waiting for the semaphore to be * signaled. If the "timeout" argument is non-zero, the thread should * only be blocked for the specified time (measured in * milliseconds). * * If the timeout argument is non-zero, the return value is the number of * milliseconds spent waiting for the semaphore to be signaled. If the * semaphore wasn't signaled within the specified time, the return value is * SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore * (i.e., it was already signaled), the function may return zero. * * Notice that lwIP implements a function with a similar name, * sys_sem_wait(), that uses the sys_arch_sem_wait() function. */ u32_t sys_arch_sem_wait( sys_sem_t sem, u32_t timeout ) { portBASE_TYPE xStatus; portTickType xTicksStart, xTicksEnd, xTicksElapsed; u32_t timespent; LWIP_ASSERT( "sys_arch_sem_wait: sem != SYS_SEM_NULL", sem != SYS_SEM_NULL ); xTicksStart = xTaskGetTickCount( ); if( timeout == 0 ) { do { xStatus = xSemaphoreTake( sem, MS_TO_TICKS( 100 ) ); } while( xStatus != pdTRUE ); } else { xStatus = xSemaphoreTake( sem, MS_TO_TICKS( timeout ) ); } /* Semaphore was signaled. */ if( xStatus == pdTRUE ) { xTicksEnd = xTaskGetTickCount( ); xTicksElapsed = xTicksEnd - xTicksStart; timespent = TICKS_TO_MS( xTicksElapsed ); } else { timespent = SYS_ARCH_TIMEOUT; } return timespent; }
unsigned long sys_jiffies( void ) { portTickType xTicks = xTaskGetTickCount( ); return ( unsigned long )TICKS_TO_MS( xTicks ); }
/** * \brief Forks a separate simple milisecond-sleep() -&- sync periodic timer * * Forks a very basic periodic timer process, that just ms-sleep()s for * the specified interval and then calls the timer function. * The new "sync timer" process execution start immediately, the ms-sleep() * is called first (so the first call to the timer function will happen * \<interval\> seconds after the call to fork_basic_utimer) * @param child_id @see fork_process() * @param desc @see fork_process() * @param make_sock @see fork_process() * @param f timer function/callback * @param param parameter passed to the timer function * @param uinterval interval in mili-seconds. * @return pid of the new process on success, -1 on error * (doesn't return anything in the child process) */ int fork_sync_utimer(int child_id, char* desc, int make_sock, utimer_function* f, void* param, int uinterval) { int pid; ticks_t ts1 = 0; ticks_t ts2 = 0; pid=fork_process(child_id, desc, make_sock); if (pid<0) return -1; if (pid==0){ /* child */ ts2 = uinterval; if (cfg_child_init()) return -1; for(;;){ if(ts2>0) sleep_us(uinterval); else sleep_us(1); ts1 = get_ticks_raw(); cfg_update(); f(TICKS_TO_MS(ts1), param); /* ticks in mili-seconds */ ts2 = uinterval - get_ticks_raw() + ts1; } } /* parent */ return pid; }
/* gettimeofday(2) equivalent, using ser internal timers (faster * but more imprecise) * WARNING: ignores tz (it's obsolete anyway)*/ int ser_gettimeofday(struct timeval* tv, struct timezone* tz) { if (likely(tv!=0)){ tv->tv_sec=last_time.tv_sec+TICKS_TO_S(*ticks-last_ticks); tv->tv_usec=last_time.tv_usec+ (TICKS_TO_MS(*ticks-last_ticks)%1000)*1000; } return 0; }
u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) { u32_t start_ticks = 0; u32_t stop_ticks = 0; u32_t ticks = 0; /* The mutex lock is quick so we don't bother with the timeout stuff here. */ sem_wait(&mbox->mutex); while (mbox->first == mbox->last) { /* no messages in mailbox, relinqush control */ sem_post(&mbox->mutex); /* Block w/ timeout while waiting for a mail to arrive in the mailbox. */ if (timeout) { /* Try to acquire the semaphore within timeout. If not return */ int pid; start_ticks = xget_clock_ticks(); pid = get_currentPID(); if (sem_timedwait(&mbox->mail, timeout)) { return SYS_ARCH_TIMEOUT; } stop_ticks = xget_clock_ticks(); } else { sem_wait (&mbox->mail); } /* now that there is a message, regain control of mailbox */ sem_wait (&mbox->mutex); } /* obtain the first message */ if (msg != NULL) { *msg = mbox->msgs[mbox->first]; } mbox->first++; if(mbox->first == SYS_MBOX_SIZE) { mbox->first = 0; } /* relinqush control of the mailbox */ sem_post(&mbox->mutex); /* find out how much time it took us */ if (stop_ticks >= start_ticks) ticks = stop_ticks - start_ticks; else ticks = (0xffffffff - start_ticks) + stop_ticks; return TICKS_TO_MS(ticks); }
static inline int db_do_submit_query(const db1_con_t* _h, const str *_query, int (*submit_query)(const db1_con_t*, const str*)) { int ret; unsigned int ms = 0; if(unlikely(cfg_get(core, core_cfg, latency_limit_action)>0)) ms = TICKS_TO_MS(get_ticks_raw()); ret = submit_query(_h, _query); if(unlikely(cfg_get(core, core_cfg, latency_limit_action)>0)) { ms = TICKS_TO_MS(get_ticks_raw()) - ms; if(ms >= cfg_get(core, core_cfg, latency_limit_action)) { LOG(cfg_get(core, core_cfg, latency_log), "alert - query execution too long [%u ms] for [%.*s]\n", ms, _query->len<50?_query->len:50, _query->s); } } return ret; }
/* * Blocks the thread until a message arrives in the mailbox, but does * not block the thread longer than "timeout" milliseconds (similar to * the sys_arch_sem_wait() function). The "msg" argument is a result * parameter that is set by the function (i.e., by doing "*msg = * ptr"). The "msg" parameter maybe NULL to indicate that the message * should be dropped. * * Note that a function with a similar name, sys_mbox_fetch(), is * implemented by lwIP. */ u32_t sys_arch_mbox_fetch( sys_mbox_t mbox, void **msg, u32_t timeout ) { void *ret_msg; portBASE_TYPE xStatus; portTickType xTicksStart, xTicksEnd, xTicksElapsed; u32_t timespent; LWIP_ASSERT( "sys_arch_mbox_fetch: mbox != SYS_MBOX_NULL", mbox != SYS_MBOX_NULL ); xTicksStart = xTaskGetTickCount( ); if( timeout == 0 ) { do { xStatus = xQueueReceive( mbox, &ret_msg, MS_TO_TICKS( 100 ) ); } while( xStatus != pdTRUE ); } else { xStatus = xQueueReceive( mbox, &ret_msg, MS_TO_TICKS( timeout ) ); } if( xStatus == pdTRUE ) { if( msg ) { *msg = ret_msg; } xTicksEnd = xTaskGetTickCount( ); xTicksElapsed = xTicksEnd - xTicksStart; timespent = TICKS_TO_MS( xTicksElapsed ); } else { if( msg ) { *msg = NULL; } timespent = SYS_ARCH_TIMEOUT; } return timespent; }
/** * \brief Forks a separate simple milisecond-sleep() periodic timer * * Forks a very basic periodic timer process, that just ms-sleep()s for * the specified interval and then calls the timer function. * The new "basic timer" process execution start immediately, the ms-sleep() * is called first (so the first call to the timer function will happen * \<interval\> seconds after the call to fork_basic_utimer) * @param child_id @see fork_process() * @param desc @see fork_process() * @param make_sock @see fork_process() * @param f timer function/callback * @param param parameter passed to the timer function * @param uinterval interval in mili-seconds. * @return pid of the new process on success, -1 on error * (doesn't return anything in the child process) */ int fork_basic_utimer(int child_id, char* desc, int make_sock, utimer_function* f, void* param, int uinterval) { int pid; ticks_t ts; pid=fork_process(child_id, desc, make_sock); if (pid<0) return -1; if (pid==0){ /* child */ if (cfg_child_init()) return -1; for(;;){ sleep_us(uinterval); cfg_update(); ts = get_ticks_raw(); f(TICKS_TO_MS(ts), param); /* ticks in mili-seconds */ } } /* parent */ return pid; }
/*! * @brief Berechnet aktuelle Mittelwerte und Varianzen und prueft nach dt ms auf bessere Bewertung * @param dt Zeit in ms bevor eine neue Bewertung erstellt wird * @param pid_param Zeiger auf den veraenderlichen PID-Parameter * @param step Wert, um den *pid_param inkrementiert wird * Neue beste Parameter werden gespeichert und vor jeder Parameteraenderung wird der Bot kurz angehalten. * Bei neuem besten Wert werden die bisher besten Parameter per LOG ausgegeben */ static void compare_weightings(const uint16_t dt, int8_t * pid_param, const int8_t step) { /* Mittelwerte und Varianzen aktualisieren */ float weight = calc_weighting(); /* nach dt ms aktuelle Bewertung mit bisher bester vergleichen */ if (timer_ms_passed_32(&ticks, dt)) { uint32_t dt_real = TIMER_GET_TICKCOUNT_32 - ticks_start; weight = weight / (float)dt_real * (dt*1000.0f/176.0f); // Bewertung normieren if (best_weight >= weight) { /* Verbesserung => die aktuellen Parameter merken */ best_weight = weight; best_Kp = Kp; best_Ki = Ki; best_Kd = Kd; /* User per LOG informieren */ LOG_INFO("Kp=%d\tKi=%d\tKd=%d\tnach %u s", best_Kp, best_Ki, best_Kd, TICKS_TO_MS(TIMER_GET_TICKCOUNT_32)/1000); // uint32_t weight_int = weight * 1000000.0f; LOG_DEBUG("weight=%lu", (uint32_t)(weight * 1000000.0f)); } /* neuen Parameter einstellen und Nachlauf abwarten */ *pid_param = (int8_t) (*pid_param + step); // uint32_t weight_int = weight * 1000000.0f; // LOG_DEBUG("weight=%lu", weight_int); wait_for_stop(); /* alten Daten verwerfen */ clear_weighting(); /* verbleibende Zeit aktualisieren */ cal_pid_ete -= dt / 1000; } }
/* * Linux epoll() poller */ REGPRM2 static void _do_poll(struct poller *p, int exp) { int status; int fd; int count; int updt_idx; int wait_time; int old_fd; /* first, scan the update list to find polling changes */ for (updt_idx = 0; updt_idx < fd_nbupdt; updt_idx++) { fd = fd_updt[updt_idx]; HA_ATOMIC_AND(&fdtab[fd].update_mask, ~tid_bit); if (!fdtab[fd].owner) { activity[tid].poll_drop++; continue; } _update_fd(fd); } fd_nbupdt = 0; /* Scan the global update list */ for (old_fd = fd = update_list.first; fd != -1; fd = fdtab[fd].update.next) { if (fd == -2) { fd = old_fd; continue; } else if (fd <= -3) fd = -fd -4; if (fd == -1) break; if (fdtab[fd].update_mask & tid_bit) done_update_polling(fd); else continue; if (!fdtab[fd].owner) continue; _update_fd(fd); } thread_harmless_now(); /* compute the epoll_wait() timeout */ if (!exp) wait_time = MAX_DELAY_MS; else if (tick_is_expired(exp, now_ms)) { activity[tid].poll_exp++; wait_time = 0; } else { wait_time = TICKS_TO_MS(tick_remain(now_ms, exp)) + 1; if (wait_time > MAX_DELAY_MS) wait_time = MAX_DELAY_MS; } /* now let's wait for polled events */ gettimeofday(&before_poll, NULL); status = epoll_wait(epoll_fd[tid], epoll_events, global.tune.maxpollevents, wait_time); tv_update_date(wait_time, status); measure_idle(); thread_harmless_end(); /* process polled events */ for (count = 0; count < status; count++) { unsigned int n; unsigned int e = epoll_events[count].events; fd = epoll_events[count].data.fd; if (!fdtab[fd].owner) { activity[tid].poll_dead++; continue; } if (!(fdtab[fd].thread_mask & tid_bit)) { /* FD has been migrated */ activity[tid].poll_skip++; epoll_ctl(epoll_fd[tid], EPOLL_CTL_DEL, fd, &ev); HA_ATOMIC_AND(&polled_mask[fd], ~tid_bit); continue; } /* it looks complicated but gcc can optimize it away when constants * have same values... In fact it depends on gcc :-( */ if (EPOLLIN == FD_POLL_IN && EPOLLOUT == FD_POLL_OUT && EPOLLPRI == FD_POLL_PRI && EPOLLERR == FD_POLL_ERR && EPOLLHUP == FD_POLL_HUP) { n = e & (EPOLLIN|EPOLLOUT|EPOLLPRI|EPOLLERR|EPOLLHUP); } else { n = ((e & EPOLLIN ) ? FD_POLL_IN : 0) | ((e & EPOLLPRI) ? FD_POLL_PRI : 0) | ((e & EPOLLOUT) ? FD_POLL_OUT : 0) | ((e & EPOLLERR) ? FD_POLL_ERR : 0) | ((e & EPOLLHUP) ? FD_POLL_HUP : 0); } /* always remap RDHUP to HUP as they're used similarly */ if (e & EPOLLRDHUP) { HA_ATOMIC_OR(&cur_poller.flags, HAP_POLL_F_RDHUP); n |= FD_POLL_HUP; } fd_update_events(fd, n); } /* the caller will take care of cached events */ }
void SleepHandler::doHibernate(uint32_t ms, bool interruptible) { // First, make sure we configure timer2 and get it running as // fast as possible. This makes the total sleep delay as // accurate as possible. // Backup timer2 settings uint8_t timsk2 = TIMSK2; uint8_t tccr2a = TCCR2A; uint8_t tccr2b = TCCR2B; // Disable timer2 interrupts, stop the timer and reset it // to normal mode. It seems that for some reason, switching to // asynchronous mode without these registers cleared can somehow // mess up the OCR2x register values... TIMSK2 = 0; TCCR2B = 0; TCCR2A = 0; // Backup the counter. There is a small race condition here // where a counter interrupt could be missed, but since we're // about to sleep for a while and timer2 probably isn't used by // anything else, that's ok. uint8_t tcnt2 = TCNT2; // Enable asynchronous mode for timer2 (uses external 32kHz // crystal. This might corrupt the settings registers, so we'll // have to (re-)set them all. // TCCR2B. uint8_t assr = ASSR; ASSR |= (1 << AS2); // Outputs disconnected, normal mode TCCR2A = 0;//(1 << WGM21) | (1 << WGM20); // Count all the way up to 0xff TCNT2 = 0; OCR2B = 0xff; // Clear any pending interrupt TIFR2 = (1 << OCF2B); // Start timer, prescaler 1024, meaning a single timer increment // is 1/32s TCCR2B = (1 << CS22) | (1 << CS21) | (1 << CS20); // Now that timer2 is running, perform any additional power // saving preparations // Disable Analag comparator uint8_t acsr = ACSR; ACSR = (1 << ACD); // Disable ADC uint8_t adcsra = ADCSRA; ADCSRA &= ~(1 << ADEN); // TODO: When re-enabling the ADC, wait for the AVDDOK bit // Disable the TX side of UART0. If the 16u2 it connects to is // powered off, it offers a path to ground, so keeping the pin // enabled and high (TTL idle) wastes around 1mA of current. To // detect if the 16u2 is powered on, see if it pulls the RX pin // high (not 100% reliable, but worst case we'll have extra // power usage). uint8_t ucsr0b = UCSR0B; if (UCSR0B & (1 << TXEN0) && !digitalRead(RX0)) UCSR0B &= ~(1 << TXEN0); // Power save mode disables the main clock, but keeps the // external clock for timer2 enabled set_sleep_mode(SLEEP_MODE_PWR_SAVE); sleep_enable(); cli(); // Enable the COMPB interrupt to wake us from sleep TIMSK2 |= (1 << OCIE2B); while (ms >= TIMER_MAX_MS) { // Sleep for a complete timer cycle. If interrupt is // false, this will always wait for a full cycle and // return true. If interrupt is true, this can return // false when another interrupt occurs. if (sleepUntilMatch(interruptible)) { ms -= TIMER_MAX_MS; hibernateMillis += TIMER_MAX_MS; } else { // Another interrupt occurred, bail out ms = 0; } } OCR2B = MS_TO_TICKS(ms); while (ASSR & (1 << OCR2BUB)) /* nothing */; // If there's sleep time left, wait for the final interrupt if (TCNT2 < OCR2B) sleepUntilMatch(interruptible); // Stop the counter. Waiting for this write to be completed has // the side effect that the TCNT2 is also safe to read now // (which contains an invalid value shortly after waking up from // sleep). TCCR2B = 0; while (ASSR & (1 << TCR2BUB)) /* nothing */; hibernateMillis += TICKS_TO_MS(TCNT2); sleep_disable(); // Clear any pending timer2 interrupts before enabling // interrupts globally, just in case TIFR2 = 0xff; sei(); // Restore timer2 settings. ASSR = assr; TCNT2 = tcnt2; TCCR2B = tccr2b; TCCR2A = tccr2a; TIMSK2 = timsk2; // Restore other settings UCSR0B = ucsr0b; ACSR = acsr; ADCSRA = adcsra; while (ADCSRB & (1 << AVDDOK)) /* nothing */; // TODO: Verify precise timings. The datasheet says that the // compare match interrupt happens the timer tick after the // match, but the asynchronous section also suggests (another?) // tick delay. Since a timer tick is fairly long (31ms), this // should be measured. }
// // Polls the lwIP stack. // void cyg_lwip_simple_poll(void) { cyg_tick_count_t ticks; cyg_uint32 delta; int i; #if LWIP_HAVE_SLIPIF && defined(CYGIMP_LWIP_SLIPIF_INSTANCE) // Poll SLIP device slipif_poll(&slipif); #endif #if PPP_SUPPORT // Poll PPP device #endif #ifdef CYGPKG_LWIP_ETH { cyg_netdevtab_entry_t *t; // Poll ethernet devices for (t = &__NETDEVTAB__[0]; t != &__NETDEVTAB_END__; t++) { struct eth_drv_sc *sc = (struct eth_drv_sc *)t->device_instance; if (sc->state & ETH_DRV_NEEDS_DELIVERY) { #if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) cyg_bool was_ctrlc_int; #endif sc->state &= ~ETH_DRV_NEEDS_DELIVERY; #if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) was_ctrlc_int = HAL_CTRLC_CHECK(sc->funs->int_vector(sc), (int) sc); if (!was_ctrlc_int) // Fall through and run normal code #endif sc->funs->deliver(sc); } } // Deliver received packets while (recv_packet_count > 0) { ethernet_input(recv_packet[recv_packet_read].p, recv_packet[recv_packet_read].netif); recv_packet_read = (recv_packet_read + 1) % MAX_RECV_PACKETS; recv_packet_count--; } } #endif // Process timers ticks = cyg_current_time(); delta = TICKS_TO_MS(ticks - last_ticks); last_ticks = ticks; // The following check 'delta > 0' rejects a potential wrap-around in the // system ticks counter. if (delta > 0) { for (i = 0; i < NUM_LWIP_TIMERS; i++) { lwip_timers[i].time += delta; if (lwip_timers[i].time >= lwip_timers[i].interval) { lwip_timers[i].timer_func(); lwip_timers[i].time -= lwip_timers[i].interval; } } } }