/* Return remain time in second. */ u_int32_t thread_timer_remain_second (struct thread *thread) { struct pal_timeval timer_now; if (thread == NULL) return 0; pal_time_tzcurrent (&timer_now, NULL); if (thread->u.sands.tv_sec - timer_now.tv_sec > 0) return thread->u.sands.tv_sec - timer_now.tv_sec; else return 0; }
/* Pick up smallest timer. */ struct pal_timeval * thread_timer_wait (struct thread_master *m, struct pal_timeval *timer_val) { struct pal_timeval timer_now; struct pal_timeval timer_min; struct pal_timeval *timer_wait; struct thread *thread; int i; timer_wait = NULL; for (i = 0; i < THREAD_TIMER_SLOT; i++) if ((thread = m->timer[i].head) != NULL) { if (! timer_wait) timer_wait = &thread->u.sands; else if (timeval_cmp (thread->u.sands, *timer_wait) < 0) timer_wait = &thread->u.sands; } if (timer_wait) { timer_min = *timer_wait; pal_time_tzcurrent (&timer_now, NULL); timer_min = timeval_subtract (timer_min, timer_now); if (timer_min.tv_sec < 0) { timer_min.tv_sec = 0; timer_min.tv_usec = 10; } *timer_val = timer_min; return timer_val; } return NULL; }
/* Add timer event thread. */ struct thread * thread_add_timer_timeval (struct lib_globals *zg, int (*func) (struct thread *), void *arg, struct pal_timeval timer) { struct thread_master *m = zg->master; struct pal_timeval timer_now; struct thread *thread; pal_assert (m != NULL); thread = thread_get (zg, THREAD_TIMER, func, arg); if (thread == NULL) return NULL; /* Do we need jitter here? */ pal_time_tzcurrent (&timer_now, NULL); timer_now.tv_sec += timer.tv_sec; timer_now.tv_usec += timer.tv_usec; while (timer_now.tv_usec >= TV_USEC_PER_SEC) { timer_now.tv_sec++; timer_now.tv_usec -= TV_USEC_PER_SEC; } /* Correct negative value. */ if (timer_now.tv_sec < 0) timer_now.tv_sec = PAL_TIME_MAX_TV_SEC; if (timer_now.tv_usec < 0) timer_now.tv_usec = PAL_TIME_MAX_TV_USEC; thread->u.sands = timer_now; /* Common process. */ thread_add_timer_common (m, thread); return thread; }
/* Add timer event thread. */ struct thread * thread_add_timer (struct lib_globals *zg, int (*func) (struct thread *), void *arg, long timer) { struct thread_master *m = zg->master; struct pal_timeval timer_now; struct thread *thread; pal_assert (m != NULL); thread = thread_get (zg, THREAD_TIMER, func, arg); if (thread == NULL) return NULL; pal_time_tzcurrent (&timer_now, NULL); timer_now.tv_sec += timer; thread->u.sands = timer_now; /* Common process. */ thread_add_timer_common (m, thread); return thread; }
/* Add timer event thread. */ struct thread * thread_add_timer (struct thread_master *master, int (*func) (struct thread *), void *arg, long timer) { struct thread_master *m = master; struct pal_timeval timer_now; struct thread *thread; assert (m != NULL); thread = thread_get (m, THREAD_TIMER, func, arg); if (thread == NULL) return NULL; /* Do we need jitter here? */ pal_time_tzcurrent (&timer_now, NULL); timer_now.tv_sec += timer; thread->u.sands = timer_now; /* Common process. */ thread_add_timer_common (m, thread); return thread; }
/* Fetch next ready thread. */ struct thread * thread_fetch (struct lib_globals *zg, struct thread *fetch) { struct thread_master *m = zg->master; int num; struct thread *thread; struct thread *next; pal_sock_set_t readfd; pal_sock_set_t writefd; pal_sock_set_t exceptfd; struct pal_timeval timer_now; struct pal_timeval timer_val; struct pal_timeval *timer_wait; struct pal_timeval timer_nowait; int i; #ifdef RTOS_DEFAULT_WAIT_TIME /* 1 sec might not be optimized */ timer_nowait.tv_sec = 1; timer_nowait.tv_usec = 0; #else timer_nowait.tv_sec = 0; timer_nowait.tv_usec = 0; #endif /* RTOS_DEFAULT_WAIT_TIME */ /* Set the global VR context to PVR. */ zg->vr_in_cxt = ipi_vr_get_privileged(zg); while (1) { /* Pending read is exception. */ if ((thread = thread_trim_head (&m->read_pend)) != NULL) return thread_run (m, thread, fetch); /* Check ready queue. */ if ((thread = thread_trim_head (&m->queue_high)) != NULL) return thread_run (m, thread, fetch); if ((thread = thread_trim_head (&m->queue_middle)) != NULL) return thread_run (m, thread, fetch); if ((thread = thread_trim_head (&m->queue_low)) != NULL) return thread_run (m, thread, fetch); /* Check all of available events. */ /* Check events. */ while ((thread = thread_trim_head (&m->event)) != NULL) thread_enqueue_high (m, thread); /* Check timer. */ pal_time_tzcurrent (&timer_now, NULL); for (i = 0; i < THREAD_TIMER_SLOT; i++) for (thread = m->timer[i].head; thread; thread = next) { next = thread->next; if (timeval_cmp (timer_now, thread->u.sands) >= 0) { thread_list_delete (&m->timer[i], thread); thread_enqueue_middle (m, thread); } #ifndef TIMER_NO_SORT else break; #endif /* TIMER_NO_SORT */ } /* Structure copy. */ readfd = m->readfd; writefd = m->writefd; exceptfd = m->exceptfd; /* Check any thing to be execute. */ if (m->queue_high.head || m->queue_middle.head || m->queue_low.head) timer_wait = &timer_nowait; else timer_wait = thread_timer_wait (m, &timer_val); /* First check for sockets. Return immediately. */ num = pal_sock_select (m->max_fd + 1, &readfd, &writefd, &exceptfd, timer_wait); /* Error handling. */ if (num < 0) { if (errno == EINTR) continue; return NULL; } /* File descriptor is readable/writable. */ if (num > 0) { /* High priority read thead. */ thread_process_fd (m, &m->read_high, &readfd, &m->readfd); /* Normal priority read thead. */ thread_process_fd (m, &m->read, &readfd, &m->readfd); /* Write thead. */ thread_process_fd (m, &m->write, &writefd, &m->writefd); } /* Low priority events. */ if ((thread = thread_trim_head (&m->event_low)) != NULL) thread_enqueue_low (m, thread); } }
/* Fetch next ready thread. */ struct thread * thread_fetch_return (struct thread_master *master, struct thread *fetch) { struct thread_master *m = master; int num; struct thread *thread; struct thread *next; fd_set readfd; fd_set writefd; fd_set exceptfd; struct pal_timeval timer_now; struct pal_timeval timer_val; struct pal_timeval *timer_wait; struct pal_timeval timer_nowait; int i; timer_nowait.tv_sec = 0; timer_nowait.tv_usec = 0; /* Pending read is exception. */ if ((thread = thread_trim_head (&m->read_pend)) != NULL) return thread_run (m, thread, fetch); /* Check ready queue. */ if ((thread = thread_trim_head (&m->queue_high)) != NULL) return thread_run (m, thread, fetch); if ((thread = thread_trim_head (&m->queue_middle)) != NULL) return thread_run (m, thread, fetch); if ((thread = thread_trim_head (&m->queue_low)) != NULL) return thread_run (m, thread, fetch); /* Check all of available events. */ /* Check events. */ while ((thread = thread_trim_head (&m->event)) != NULL) thread_enqueue_high (m, thread); /* Check timer. */ pal_time_tzcurrent (&timer_now, NULL); for (i = 0; i < THREAD_TIMER_SLOT; i++) for (thread = m->timer[i].head; thread; thread = next) { next = thread->next; if (timeval_cmp (timer_now, thread->u.sands) >= 0) { thread_list_delete (&m->timer[i], thread); thread_enqueue_middle (m, thread); } #ifndef TIMER_NO_SORT else break; #endif /* TIMER_NO_SORT */ } /* Structure copy. */ readfd = m->readfd; writefd = m->writefd; exceptfd = m->exceptfd; /* Check any thing to be execute. */ if (m->queue_high.head || m->queue_middle.head || m->queue_low.head) timer_wait = &timer_nowait; else timer_wait = thread_timer_wait (m, &timer_val); timer_wait = &timer_nowait; /* First check for sockets. Return immediately. */ num = select (m->max_fd + 1, &readfd, &writefd, &exceptfd, timer_wait); /* Error handling. */ if (num < 0) { return NULL; } /* File descriptor is readable/writable. */ if (num > 0) { /* High priority read thead. */ thread_process_fd (m, &m->read_high, &readfd, &m->readfd); /* Normal priority read thead. */ thread_process_fd (m, &m->read, &readfd, &m->readfd); /* Write thead. */ thread_process_fd (m, &m->write, &writefd, &m->writefd); } /* Low priority events. */ if ((thread = thread_trim_head (&m->event_low)) != NULL) thread_enqueue_low (m, thread); return NULL; }