apps/streamer/event.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
00003  *
00004  *  This program is free software: you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation, either version 3 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 
00018 #include <stdlib.h>
00019 #include <stdio.h>
00020 #include <sys/time.h>
00021 #include <sys/types.h>
00022 #include <unistd.h>
00023 
00024 #include "event.h"
00025 
00026 static struct event *time_event_list = NULL;
00027 static struct event *fd_event_list = NULL;
00028 static struct event *always_event_list = NULL;
00029 static int end_loop = 0;
00030 
00031 int time_diff( time_ref *tr_start, time_ref *tr_end )
00032 {
00033         return ( ( tr_end->tv_sec - tr_start->tv_sec ) * 1000000
00034                 + tr_end->tv_usec - tr_start->tv_usec + 500 ) / 1000;
00035 }
00036 
00037 int time_ago( time_ref *tr )
00038 {
00039         struct timeval now;
00040 
00041         gettimeofday( &now, NULL );
00042         return time_diff( tr, &now );
00043 }
00044 
00045 void time_now( time_ref *tr )
00046 {
00047         gettimeofday( (struct timeval *)tr, NULL );
00048 }
00049 
00050 void time_add( time_ref *tr, int msec )
00051 {
00052         tr->tv_sec += msec / 1000;
00053         tr->tv_usec += ( msec % 1000 ) * 1000;
00054 }
00055 
00056 void time_future( time_ref *tr, int msec )
00057 {
00058         gettimeofday( tr, NULL );
00059         time_add( tr, msec );
00060 }
00061 
00062 static struct event *new_event( callback f, void *d )
00063 {
00064         struct event *e;
00065 
00066         e = (struct event *)malloc( sizeof( struct event ) );
00067         e->next = NULL;
00068         e->prev = NULL;
00069         e->type = 0;
00070         e->flags = 0;
00071         e->func = f;
00072         e->data = d;
00073         return e;
00074 }
00075 
00076 static void strip_events( struct event **list )
00077 {
00078         struct event *e, *n;
00079 
00080         for( e = *list; e; e = n )
00081         {
00082                 n = e->next;
00083                 if( e->flags & EVENT_F_REMOVE )
00084                 {
00085                         if( e->next ) e->next->prev = e->prev;
00086                         if( e->prev ) e->prev->next = e->next;
00087                         else *list = e->next;
00088                 }
00089         }
00090 }
00091 
00092 struct event *add_timer_event( int msec, unsigned int flags, callback f, void *d )
00093 {
00094         struct event *e;
00095 
00096         e = new_event( f, d );
00097         e->type = EVENT_TIME;
00098         e->flags = flags;
00099         e->ev.time.ival = msec;
00100         e->next = time_event_list;
00101         if( e->next ) e->next->prev = e;
00102         time_event_list = e;
00103         time_now( &e->ev.time.fire );
00104         resched_event( e, NULL );
00105         return e;
00106 }
00107 
00108 struct event *add_alarm_event( time_ref *t, unsigned int flags, callback f, void *d )
00109 {
00110         struct event *e;
00111 
00112         e = new_event( f, d );
00113         e->type = EVENT_TIME;
00114         e->flags = flags | EVENT_F_ONESHOT;
00115         e->next = time_event_list;
00116         if( e->next ) e->next->prev = e;
00117         time_event_list = e;
00118         resched_event( e, t );
00119         return e;
00120 }
00121 
00122 void resched_event( struct event *e, time_ref *tr )
00123 {
00124         if( tr )
00125                 e->ev.time.fire = *tr;
00126         else if( e->flags & EVENT_F_ENABLED )
00127                 time_add( &e->ev.time.fire, e->ev.time.ival );
00128         else
00129                 time_future( &e->ev.time.fire, e->ev.time.ival );
00130 
00131         e->flags &= ~EVENT_F_REMOVE;
00132         e->flags |= EVENT_F_ENABLED;
00133 }
00134 
00135 struct event *add_fd_event( int fd, int write, unsigned int flags, callback f, void *d )
00136 {
00137         struct event *e;
00138 
00139         e = new_event( f, d );
00140         e->type = EVENT_FD;
00141         e->flags = flags | EVENT_F_ENABLED;
00142         e->ev.fd.fd = fd;
00143         e->ev.fd.write = write;
00144         e->next = fd_event_list;
00145         if( e->next ) e->next->prev = e;
00146         fd_event_list = e;
00147         return e;
00148 }
00149 
00150 struct event *add_always_event( unsigned int flags, callback f, void *d )
00151 {
00152         struct event *e;
00153 
00154         e = new_event( f, d );
00155         e->type = EVENT_ALWAYS;
00156         e->flags = flags | EVENT_F_ENABLED;
00157         e->next = always_event_list;
00158         if( e->next ) e->next->prev = e;
00159         always_event_list = e;
00160         return e;
00161 }
00162 
00163 void remove_event( struct event *e )
00164 {
00165         e->flags |= EVENT_F_REMOVE;
00166         e->flags &= ~EVENT_F_RUNNING;
00167 }
00168 
00169 void set_event_interval( struct event *e, int msec )
00170 {
00171         e->ev.time.ival = msec;
00172         if( e->flags & EVENT_F_ENABLED ) resched_event( e, NULL );
00173 }
00174 
00175 void set_event_enabled( struct event *e, int enabled )
00176 {
00177         e->flags &= ~EVENT_F_ENABLED;
00178         if( enabled ) e->flags |= EVENT_F_ENABLED;
00179 }
00180 
00181 int get_event_enabled( struct event *e )
00182 {
00183         return e->flags & EVENT_F_ENABLED ? 1 : 0;
00184 }
00185 
00186 void exit_event_loop(void)
00187 {
00188         end_loop = 1;
00189 }
00190 
00191 void event_loop( int single )
00192 {
00193         struct timeval t, *st;
00194         struct event *e;
00195         int diff, nexttime = 0, highfd, ret;
00196         fd_set rfds, wfds;
00197 
00198         end_loop = 0;
00199 
00200         do {
00201                 st = NULL;
00202                 /* check how long the timeout should be */
00203                 for( e = time_event_list; e; e = e->next )
00204                         if( e->flags & EVENT_F_ENABLED )
00205                         {
00206                                 diff = -time_ago( &e->ev.time.fire );
00207                                 st = &t;
00208                                 if( diff < 5 ) diff = 0;
00209                                 if( ! st || diff < nexttime ) nexttime = diff;
00210                                 e->flags |= EVENT_F_RUNNING;
00211                         } else e->flags &= ~EVENT_F_RUNNING;
00212                 for( e = always_event_list; e; e = e->next )
00213                         if( e->flags & EVENT_F_ENABLED )
00214                         {
00215                                 st = &t;
00216                                 nexttime = 0;
00217                                 e->flags |= EVENT_F_RUNNING;
00218                         } else e->flags &= ~EVENT_F_RUNNING;
00219                 if( st )
00220                 {
00221                         t.tv_sec = nexttime / 1000;
00222                         t.tv_usec = ( nexttime % 1000 ) * 1000;
00223                 }
00224                 FD_ZERO( &rfds );
00225                 FD_ZERO( &wfds );
00226                 highfd = -1;
00227                 /* This is all so ugly...  It should use poll() eventually. */
00228                 for( e = fd_event_list; e; e = e->next )
00229                 {
00230                         if( e->flags & EVENT_F_ENABLED )
00231                         {
00232                                 FD_SET( e->ev.fd.fd,
00233                                         e->ev.fd.write ? &wfds : &rfds );
00234                                 if( e->ev.fd.fd > highfd )
00235                                         highfd = e->ev.fd.fd;
00236                                 e->flags |= EVENT_F_RUNNING;
00237                         } else e->flags &= ~EVENT_F_RUNNING;
00238                 }
00239                 ret = select( highfd + 1, &rfds, &wfds, NULL, st );
00240                 for( e = time_event_list; e; e = e->next )
00241                 {
00242                         if( ! ( e->flags & EVENT_F_RUNNING ) ) continue;
00243                         if( end_loop ) break;
00244                         diff = -time_ago( &e->ev.time.fire );
00245                         if( diff < 5 )
00246                         {
00247                                 if( ! ( e->flags & EVENT_F_ONESHOT ) )
00248                                         resched_event( e, NULL );
00249                                 else e->flags |= EVENT_F_REMOVE;
00250                                 (*e->func)( e, e->data );
00251                         }
00252                 }
00253                 for( e = always_event_list; e; e = e->next )
00254                 {
00255                         if( ! ( e->flags & EVENT_F_RUNNING ) ) continue;
00256                         if( end_loop ) break;
00257                         if( e->flags & EVENT_F_ONESHOT )
00258                                 e->flags |= EVENT_F_REMOVE;
00259                         (*e->func)( e, e->data );
00260                 }
00261                 if( ret > 0 ) for( e = fd_event_list; e; e = e->next )
00262                 {
00263                         if( ! ( e->flags & EVENT_F_RUNNING ) ) continue;
00264                         if( end_loop ) break;
00265                         if( FD_ISSET( e->ev.fd.fd,
00266                                         e->ev.fd.write ? &wfds : &rfds ) )
00267                         {
00268                                 if( e->flags & EVENT_F_ONESHOT )
00269                                         e->flags |= EVENT_F_REMOVE;
00270                                 (*e->func)( e, e->data );
00271                         }
00272                 }
00273                 strip_events( &time_event_list );
00274                 strip_events( &fd_event_list );
00275                 strip_events( &always_event_list );
00276         } while( ! end_loop && ! single );
00277 }

Generated on Fri Nov 28 00:06:22 2008 for elphel by  doxygen 1.5.1