Commit c5ae5400 authored by Simon Morlat's avatar Simon Morlat

main loop implementation now done (untested)

parent a3ad258c
......@@ -53,7 +53,7 @@ fi
# Checks for library functions.
AC_CHECK_LIB(rt, clock_gettime)
AM_CONDITIONAL(BUILD_TESTS,test x$found_cunit = xyes)
......
......@@ -22,4 +22,11 @@
#include "belle-sip/list.h"
#include "belle-sip/mainloop.h"
#undef TRUE
#define TRUE 1
#undef FALSE
#define FALSE 0
#endif
......@@ -20,11 +20,12 @@
#define BELLE_SIP_MAINLOOP_H
#define BELLE_SIP_EVENT_READ 1
#define BELLE_SIP_EVENT_ERROR (1<<1)
#define BELLE_SIP_EVENT_WRITE (1<<1)
#define BELLE_SIP_EVENT_ERROR (1<<2)
typedef struct belle_sip_source belle_sip_source_t;
typedef int (*belle_sip_source_func_t)(void *user_data, int events);
typedef int (*belle_sip_source_func_t)(void *user_data, unsigned int events);
belle_sip_source_t * belle_sip_timeout_source_new(belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms);
......
......@@ -6,6 +6,8 @@
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include "belle-sip/list.h"
......@@ -150,6 +152,8 @@ static inline void belle_sip_fatal(const char *fmt,...)
char * belle_sip_concat (const char *str, ...);
uint64_t belle_sip_time_ms(void);
#ifdef __cplusplus
}
#endif
......
......@@ -19,37 +19,62 @@
#include "belle-sip/belle-sip.h"
#include "belle_sip_internal.h"
#include <unistd.h>
#include <poll.h>
struct belle_sip_source{
belle_sip_list_t node;
int fd;
int revents;
unsigned int events;
int timeout;
void *data;
uint64_t expire_ms;
int index; /* index in pollfd table */
belle_sip_source_func_t notify;
void (*on_remove)(belle_sip_source_t *);
};
void belle_sip_source_destroy(belle_sip_source_t *obj){
if (obj->node.next || obj->node.prev){
belle_sip_fatal("Destroying source currently used in main loop !");
}
belle_sip_free(obj);
}
belle_sip_source_t * belle_sip_timeout_source_new(belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms){
static belle_sip_source_t * belle_sip_fd_source_new(belle_sip_source_func_t func, void *data, int fd, unsigned int events, unsigned int timeout_value_ms){
belle_sip_source_t *s=belle_sip_new0(belle_sip_source_t);
s->fd=-1;
s->fd=fd;
s->events=events;
s->timeout=timeout_value_ms;
s->data=data;
s->notify=func;
return s;
}
belle_sip_source_t * belle_sip_timeout_source_new(belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms){
return belle_sip_fd_source_new(func,data,-1,0,timeout_value_ms);
}
struct belle_sip_main_loop{
belle_sip_source_t *sources;
belle_sip_source_t *control;
int nsources;
int run;
int control_fds[2];
};
static int main_loop_done(void *data, unsigned int events){
belle_sip_debug("Got data on control fd...");
return TRUE;
}
belle_sip_main_loop_t *belle_sip_main_loop_new(void){
belle_sip_main_loop_t*m=belle_sip_new0(belle_sip_main_loop_t);
if (pipe(m->control_fds)==-1){
belle_sip_fatal("Could not create control pipe.");
}
m->control=belle_sip_fd_source_new (main_loop_done,NULL,m->control_fds[0],BELLE_SIP_EVENT_READ,-1);
belle_sip_main_loop_add_source(m,m->control);
return m;
}
......@@ -58,11 +83,19 @@ void belle_sip_main_loop_add_source(belle_sip_main_loop_t *ml, belle_sip_source_
belle_sip_fatal("Source is already linked somewhere else.");
return;
}
if (source->timeout>0){
source->expire_ms=belle_sip_time_ms()+source->timeout;
}
ml->sources=(belle_sip_source_t*)belle_sip_list_append_link((belle_sip_list_t*)ml->sources,(belle_sip_list_t*)source);
ml->nsources++;
}
void belle_sip_main_loop_remove_source(belle_sip_main_loop_t *ml, belle_sip_source_t *source){
ml->sources=(belle_sip_source_t*)belle_sip_list_remove_link((belle_sip_list_t*)ml->sources,(belle_sip_list_t*)source);
ml->nsources--;
if (source->on_remove)
source->on_remove(source);
}
void belle_sip_main_loop_add_timeout(belle_sip_main_loop_t *ml, belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms){
......@@ -70,3 +103,113 @@ void belle_sip_main_loop_add_timeout(belle_sip_main_loop_t *ml, belle_sip_source
s->on_remove=belle_sip_source_destroy;
belle_sip_main_loop_add_source(ml,s);
}
/*
Poll() based implementation of event loop.
*/
static int belle_sip_event_to_poll(unsigned int events){
int ret=0;
if (events & BELLE_SIP_EVENT_READ)
ret|=POLLIN;
if (events & BELLE_SIP_EVENT_WRITE)
ret|=POLLOUT;
if (events & BELLE_SIP_EVENT_ERROR)
ret|=POLLERR;
return ret;
}
static unsigned int belle_sip_poll_to_event(short events){
unsigned int ret=0;
if (events & POLLIN)
ret|=BELLE_SIP_EVENT_READ;
if (events & POLLOUT)
ret|=BELLE_SIP_EVENT_WRITE;
if (events & POLLERR)
ret|=BELLE_SIP_EVENT_ERROR;
return ret;
}
void belle_sip_main_loop_iterate(belle_sip_main_loop_t *ml){
struct pollfd *pfd=(struct pollfd*)alloca(ml->nsources*sizeof(struct pollfd));
int i=0;
belle_sip_source_t *s,*next;
uint64_t min_time_ms=(uint64_t)-1;
int duration=-1;
int ret;
uint64_t cur;
/*prepare the pollfd table */
for(s=ml->sources;s!=NULL;s=(belle_sip_source_t*)s->node.next){
if (s->fd!=-1){
pfd[i].fd=s->fd;
pfd[i].events=belle_sip_event_to_poll (s->events);
pfd[i].revents=0;
s->index=i;
++i;
}
if (s->timeout>0){
if (min_time_ms>s->expire_ms){
min_time_ms=s->expire_ms;
}
}
}
if (min_time_ms!=(uint64_t)-1 ){
/* compute the amount of time to wait for shortest timeout*/
cur=belle_sip_time_ms();
int64_t diff=min_time_ms-cur;
if (diff>0)
duration=(int)diff;
else
duration=0;
}
/* do the poll */
ret=poll(pfd,i,duration);
if (ret==-1 && errno!=EINTR){
belle_sip_error("poll() error: %s",strerror(errno));
return;
}
cur=belle_sip_time_ms();
/* examine poll results*/
for(s=ml->sources;s!=NULL;s=next){
unsigned revents=0;
next=(belle_sip_source_t*)s->node.next;
if (s->fd!=-1){
if (pfd[s->index].revents!=0){
revents=belle_sip_poll_to_event(pfd[s->index].revents);
}
}
if (revents!=0 || (s->timeout>0 && cur>=s->expire_ms)){
ret=s->notify(s->data,revents);
if (ret==0){
/*this source needs to be removed*/
belle_sip_main_loop_remove_source(ml,s);
}else if (revents==0){
/*timeout needs to be started again */
s->expire_ms+=s->timeout;
}
}
}
}
void belle_sip_main_loop_run(belle_sip_main_loop_t *ml){
ml->run=1;
while(ml->run){
belle_sip_main_loop_iterate(ml);
}
}
void belle_sip_main_loop_quit(belle_sip_main_loop_t *ml){
ml->run=0;
write(ml->control_fds[1],"a",1);
}
void belle_sip_main_loop_destroy(belle_sip_main_loop_t *ml){
belle_sip_main_loop_remove_source (ml,ml->control);
belle_sip_source_destroy(ml->control);
close(ml->control_fds[0]);
close(ml->control_fds[1]);
belle_sip_free(ml);
}
......@@ -2,6 +2,8 @@
#include "belle_sip_internal.h"
#include <time.h>
static FILE *__log_file=0;
......@@ -401,3 +403,18 @@ void belle_sip_free(void *ptr){
free(ptr);
}
uint64_t belle_sip_time_ms(void){
struct timespec ts;
static int clock_id=CLOCK_MONOTONIC;
if (clock_gettime(clock_id,&ts)==-1){
belle_sip_error("clock_gettime() error for clock_id=%i: %s",clock_id,strerror(errno));
if (clock_id==CLOCK_MONOTONIC){
clock_id=CLOCK_REALTIME;
return belle_sip_time_ms();
}
return 0;
}
return (ts.tv_sec*1000LL) + (ts.tv_nsec/1000000LL);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment