4 * @brief Implementation of event_queue_t
9 * Copyright (C) 2005-2006 Martin Willi
10 * Copyright (C) 2005 Jan Hutter
11 * Hochschule fuer Technik Rapperswil
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27 #include "event_queue.h"
30 #include <utils/linked_list.h>
34 typedef struct event_t event_t
;
37 * Event containing a job and a schedule time
41 * Time to fire the event.
46 * Every event has its assigned job.
52 * destroy an event and its job
54 static void event_destroy(event_t
*event
)
56 event
->job
->destroy(event
->job
);
60 typedef struct private_event_queue_t private_event_queue_t
;
63 * Private Variables and Functions of event_queue_t class.
65 struct private_event_queue_t
{
72 * The events are stored in a linked list of type linked_list_t.
77 * Access to linked_list is locked through this mutex.
79 pthread_mutex_t mutex
;
82 * If the queue is empty or an event has not to be fired
83 * a thread has to wait.
85 * This condvar is used to wake up such a thread.
87 pthread_cond_t condvar
;
91 * Returns the difference of to timeval structs in milliseconds
93 static long time_difference(struct timeval
*end_time
, struct timeval
*start_time
)
98 s
= (end_time
->tv_sec
- start_time
->tv_sec
);
99 us
= (end_time
->tv_usec
- start_time
->tv_usec
);
100 return ((s
* 1000) + us
/1000);
104 * Implements event_queue_t.get_count
106 static int get_count(private_event_queue_t
*this)
109 pthread_mutex_lock(&(this->mutex
));
110 count
= this->list
->get_count(this->list
);
111 pthread_mutex_unlock(&(this->mutex
));
116 * Implements event_queue_t.get
118 static job_t
*get(private_event_queue_t
*this)
121 timeval_t current_time
;
122 event_t
* next_event
;
126 pthread_mutex_lock(&(this->mutex
));
130 while(this->list
->get_count(this->list
) == 0)
132 /* add mutex unlock handler for cancellation, enable cancellation */
133 pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock
, (void*)&(this->mutex
));
134 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, &oldstate
);
136 pthread_cond_wait( &(this->condvar
), &(this->mutex
));
138 /* reset cancellation, remove mutex-unlock handler (without executing) */
139 pthread_setcancelstate(oldstate
, NULL
);
140 pthread_cleanup_pop(0);
143 this->list
->get_first(this->list
, (void **)&next_event
);
145 gettimeofday(¤t_time
, NULL
);
146 long difference
= time_difference(¤t_time
,&(next_event
->time
));
149 timeout
.tv_sec
= next_event
->time
.tv_sec
;
150 timeout
.tv_nsec
= next_event
->time
.tv_usec
* 1000;
152 /* add mutex unlock handler for cancellation, enable cancellation */
153 pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock
, (void*)&(this->mutex
));
154 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, &oldstate
);
156 pthread_cond_timedwait(&(this->condvar
), &(this->mutex
), &timeout
);
158 /* reset cancellation, remove mutex-unlock handler (without executing) */
159 pthread_setcancelstate(oldstate
, NULL
);
160 pthread_cleanup_pop(0);
164 /* event available */
165 this->list
->remove_first(this->list
, (void **)&next_event
);
166 job
= next_event
->job
;
171 pthread_cond_signal( &(this->condvar
));
172 pthread_mutex_unlock(&(this->mutex
));
178 * Implements function add_absolute of event_queue_t.
179 * See #event_queue_s.add_absolute for description.
181 static void add_absolute(private_event_queue_t
*this, job_t
*job
, timeval_t time
)
184 event_t
*current_event
;
185 iterator_t
*iterator
;
188 event
= malloc_thing(event_t
);
192 pthread_mutex_lock(&(this->mutex
));
194 /* while just used to break out */
197 if (this->list
->get_count(this->list
) == 0)
199 this->list
->insert_first(this->list
,event
);
203 /* check last entry */
204 this->list
->get_last(this->list
,(void **) ¤t_event
);
206 if (time_difference(&(event
->time
), &(current_event
->time
)) >= 0)
208 /* my event has to be fired after the last event in list */
209 this->list
->insert_last(this->list
,event
);
213 /* check first entry */
214 this->list
->get_first(this->list
,(void **) ¤t_event
);
216 if (time_difference(&(event
->time
), &(current_event
->time
)) < 0)
218 /* my event has to be fired before the first event in list */
219 this->list
->insert_first(this->list
,event
);
223 iterator
= this->list
->create_iterator(this->list
,TRUE
);
224 iterator
->iterate(iterator
, (void**)¤t_event
);
225 /* first element has not to be checked (already done) */
226 while(iterator
->iterate(iterator
, (void**)¤t_event
))
228 if (time_difference(&(event
->time
), &(current_event
->time
)) <= 0)
230 /* my event has to be fired before the current event in list */
231 iterator
->insert_before(iterator
,event
);
235 iterator
->destroy(iterator
);
239 pthread_cond_signal( &(this->condvar
));
240 pthread_mutex_unlock(&(this->mutex
));
244 * Implements event_queue_t.add_relative.
246 static void add_relative(event_queue_t
*this, job_t
*job
, u_int32_t ms
)
248 timeval_t current_time
;
251 time_t s
= ms
/ 1000;
252 suseconds_t us
= (ms
- s
* 1000) * 1000;
254 gettimeofday(¤t_time
, NULL
);
256 time
.tv_usec
= (current_time
.tv_usec
+ us
) % 1000000;
257 time
.tv_sec
= current_time
.tv_sec
+ (current_time
.tv_usec
+ us
)/1000000 + s
;
259 this->add_absolute(this, job
, time
);
264 * Implements event_queue_t.destroy.
266 static void event_queue_destroy(private_event_queue_t
*this)
268 this->list
->destroy_function(this->list
, (void*)event_destroy
);
273 * Documented in header
275 event_queue_t
*event_queue_create()
277 private_event_queue_t
*this = malloc_thing(private_event_queue_t
);
279 this->public.get_count
= (int (*) (event_queue_t
*event_queue
)) get_count
;
280 this->public.get
= (job_t
*(*) (event_queue_t
*event_queue
)) get
;
281 this->public.add_absolute
= (void (*) (event_queue_t
*event_queue
, job_t
*job
, timeval_t time
)) add_absolute
;
282 this->public.add_relative
= (void (*) (event_queue_t
*event_queue
, job_t
*job
, u_int32_t ms
)) add_relative
;
283 this->public.destroy
= (void (*) (event_queue_t
*event_queue
)) event_queue_destroy
;
285 this->list
= linked_list_create();
286 pthread_mutex_init(&(this->mutex
), NULL
);
287 pthread_cond_init(&(this->condvar
), NULL
);
289 return (&this->public);