== AsteriskSource/SelectPoll == * select * select(0,NULL,NULL,NULL,NULL) {{{ If the readfs , writefs , and errorfds arguments are all null pointers and the timeout argument is a null pointer, select() blocks until interrupted by a signal. }}} {{{ The call returns the number of `ready' FDs found, and the three fdsets are modified in-place, with only the ready FDs left in the sets. Use the `FD_ISSET' macro to test the returned sets. }}} * poll * * int poll(struct poolfd *ufds, unsigned int nfds, int timeout); {{{ #define POLLIN 0x0001 // 읽을 데이타가 있다. #define POLLPRI 0x0002 // 긴급한 읽을 데이타가 있다. #define POLLOUT 0x0004 // 쓰기가 봉쇄(block)가 아니다. #define POLLERR 0x0008 // 에러발생 #define POLLHUP 0x0010 // 연결이 끊겼음 #define POLLNVAL 0x0020 // 파일지시자가 열리지 않은것같은 // Invalid request (잘못된 요청) }}} * 마지막 아규먼트인 timeout 는 select 의 time 와 같은 역할을 한다. {{{ If none of the defined events have occurred on any selected file descriptor, poll() shall wait at least timeout milliseconds for an event to occur on any of the selected file descriptors. If the value of timeout is 0, poll() shall return immediately. If the value of timeout is -1, poll() shall block until a requested event occurs or until the call is interrupted. }}} {{{ RETURN value Upon successful completion, poll() shall return a non-negative value. A positive value indicates the total number of file descriptors that have been selected (that is, file descriptors for which the revents member is non-zero). A value of 0 indicates that the call timed out and no file descriptors have been selected. Upon failure, poll() shall return -1 and set errno to indicate the error. }}} == schedule.c == * chan_sip.c * static void *do_monitor(void *data) * sched = sched_context_create(); * res = ast_sched_wait(sched); * res = ast_io_wait(io, res); * if (res >= 0) ast_io_wait 에서 오류가 발생하지 않으면 * ast_sched_runq(sched); * struct sched_context *sched_context_create(void) {{{ struct sched_context *sched_context_create(void) { struct sched_context *tmp; tmp = malloc(sizeof(struct sched_context)); if (tmp) { tmp->eventcnt = 1; no. of events processed tmp->schedcnt = 0; no. of outstanding schedule events tmp->schedq = NULL; schedule entry and main queue #ifdef SCHED_MAX_CACHE tmp->schedc = NULL; tmp->schedccnt = 0; #endif } return tmp; } }}} * eventcnt * sched_context_create 에서 1 로 설정 * ast_sched_add 시 1 씩 증가 * id 로 사용함 (queue 에 들어온 순서임) * ast_sched_del 에서 id 를 사용하여 제거함. * schedcnt * queue 에 있는 event 의 갯수임. * sched_context_create 에서 0 로 설정 * schedule 시 1 씩 증가 * ast_sched_del 에서 1 감소 * ast_sched_runq 에서 수행시킨 만큼 감소 * int ast_sched_wait(struct sched_context *con) {{{ int ast_sched_wait(struct sched_context *con) { /* * Return the number of milliseconds * until the next scheduled event */ struct timeval tv; int ms; DEBUG(ast_log(LOG_DEBUG, "ast_sched_wait()\n")); if (!con->schedq) return -1; if (gettimeofday(&tv, NULL) < 0) { /* This should never happen */ return 0; }; ms = (con->schedq->when.tv_sec - tv.tv_sec) * 1000; ms += (con->schedq->when.tv_usec - tv.tv_usec) / 1000; if (ms < 0) ms = 0; return ms; } }}} * * schedule queue 에 아무것도 없으면 return -1 * 현재의 시간을 tv 에 assign * schedule queue 의 첫번째 event 의 when 이 이미 지난 시간이면 return 0 * 아니면 남은 시간을 return * int ast_sched_runq(struct sched_context *con) * x=0; * for * schedule queue 에 event 가 없으면 break * tv 에 현재 시간 assign * 현재 시간 이전으로 when 이 설정된 event 가 있으면 * current = con->schedq; * con->schedq = con->schedq->next; * con->schedcnt--; * current->callback(current->data) * sched_release(con, current); * or schedule(con, current); * x++; * 없으면 break * return x; * chan_sip.c * ast_io_add(io, sipsock, sipsock_read, AST_IO_IN, NULL); * res = ast_io_wait(io, res); * static int sipsock_read(int *id, int fd, short events, void *ignore) * handle_request(p, &req, &sin); * register_verify(p, sin, req) * parse_contact(p, peer, req) * p->expire = ast_sched_add(sched, expirey * 1000, expire_register, p); * int ast_sched_add(struct sched_context *con, int when, ast_sched_cb callback, void *data) * tmp->id = con->eventcnt++; * tmp->callback = callback; * tmp->data = data; * tmp->resched = when; * sched_settime(&tmp->when, when) * 현재 시간에 when 을 더하여 tmp->when 에 설정 * schedule(con, tmp); * schedq 는 시간 순의 events list 임. * 새로 추가하는 event 의 시간과 현재 있는 events 들의 시간을 비교하여 맞는 자리에 추가함. * return tmp->id; * static struct sched *sched_alloc(struct sched_context *con) {{{ static struct sched *sched_alloc(struct sched_context *con) { /* * We keep a small cache of schedule entries * to minimize the number of necessary malloc()'s */ struct sched *tmp; #ifdef SCHED_MAX_CACHE if (con->schedc) { tmp = con->schedc; con->schedc = con->schedc->next; con->schedccnt--; } else #endif tmp = malloc(sizeof(struct sched)); return tmp; } }}} * static inline int sched_settime(struct timeval *tv, int when) {{{ static inline int sched_settime(struct timeval *tv, int when) { if (gettimeofday(tv, NULL) < 0) { /* This shouldn't ever happen, but let's be sure */ ast_log(LOG_NOTICE, "gettimeofday() failed!\n"); return -1; } tv->tv_sec += when/1000; tv->tv_usec += (when % 1000) * 1000; if (tv->tv_usec > 1000000) { tv->tv_sec++; tv->tv_usec-= 1000000; } return 0; } }}} * static void schedule(struct sched_context *con, struct sched *s) {{{ static void schedule(struct sched_context *con, struct sched *s) { /* * Take a sched structure and put it in the * queue, such that the soonest event is * first in the list. */ struct sched *last=NULL; struct sched *current=con->schedq; while(current) { if (SOONER(s->when, current->when)) break; last = current; current = current->next; } /* Insert this event into the schedule */ s->next = current; if (last) last->next = s; else con->schedq = s; con->schedcnt++; } }}} * static void sched_release(struct sched_context *con, struct sched *tmp) {{{ static void sched_release(struct sched_context *con, struct sched *tmp) { /* * Add to the cache, or just free() if we * already have too many cache entries */ #ifdef SCHED_MAX_CACHE if (con->schedccnt < SCHED_MAX_CACHE) { tmp->next = con->schedc; con->schedc = tmp; con->schedccnt++; } else #endif free(tmp); } }}}