4 * @brief Implementation of event_queue_t
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 #include "event_queue.h"
29 #include <utils/linked_list.h>
33 typedef struct event_t event_t
;
36 * @brief Represents an event as it is stored in the event queue.
38 * A event consists of a event time and an assigned job object.
43 * Time to fire the event.
48 * Every event has its assigned job.
53 * @brief Destroys a event_t object.
55 * @param event_t calling object
57 void (*destroy
) (event_t
*event
);
62 * implements event_t.destroy
64 static void event_destroy(event_t
*event
)
70 * @brief Creates a event for a specific time
72 * @param time absolute time to fire the event
73 * @param job job to add to job-queue at specific time
75 * @returns created event_t object
77 static event_t
*event_create(timeval_t time
, job_t
*job
)
79 event_t
*this = malloc_thing(event_t
);
81 this->destroy
= event_destroy
;
89 typedef struct private_event_queue_t private_event_queue_t
;
92 * Private Variables and Functions of event_queue_t class.
95 struct private_event_queue_t
{
102 * The events are stored in a linked list of type linked_list_t.
107 * Access to linked_list is locked through this mutex.
109 pthread_mutex_t mutex
;
112 * If the queue is empty or an event has not to be fired
113 * a thread has to wait.
115 * This condvar is used to wake up such a thread.
117 pthread_cond_t condvar
;
121 * Returns the difference of to timeval structs in microseconds
123 * @param end_time end time
124 * @param start_time start time
126 * @warning this function is also defined in the tester class
127 * In later improvements, this function can be added to a general
130 * @return difference in microseconds (end time - start time)
132 static long time_difference(struct timeval
*end_time
, struct timeval
*start_time
)
134 long seconds
, microseconds
;
136 seconds
= (end_time
->tv_sec
- start_time
->tv_sec
);
137 microseconds
= (end_time
->tv_usec
- start_time
->tv_usec
);
138 return ((seconds
* 1000000) + microseconds
);
143 * Implements event_queue_t.get_count
145 static int get_count (private_event_queue_t
*this)
148 pthread_mutex_lock(&(this->mutex
));
149 count
= this->list
->get_count(this->list
);
150 pthread_mutex_unlock(&(this->mutex
));
155 * Implements event_queue_t.get
157 static job_t
*get(private_event_queue_t
*this)
160 timeval_t current_time
;
161 event_t
* next_event
;
165 pthread_mutex_lock(&(this->mutex
));
169 while(this->list
->get_count(this->list
) == 0)
171 /* add mutex unlock handler for cancellation, enable cancellation */
172 pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock
, (void*)&(this->mutex
));
173 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, &oldstate
);
175 pthread_cond_wait( &(this->condvar
), &(this->mutex
));
177 /* reset cancellation, remove mutex-unlock handler (without executing) */
178 pthread_setcancelstate(oldstate
, NULL
);
179 pthread_cleanup_pop(0);
182 this->list
->get_first(this->list
,(void **) &next_event
);
184 gettimeofday(¤t_time
,NULL
);
185 long difference
= time_difference(¤t_time
,&(next_event
->time
));
188 timeout
.tv_sec
= next_event
->time
.tv_sec
;
189 timeout
.tv_nsec
= next_event
->time
.tv_usec
* 1000;
191 /* add mutex unlock handler for cancellation, enable cancellation */
192 pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock
, (void*)&(this->mutex
));
193 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, &oldstate
);
195 pthread_cond_timedwait( &(this->condvar
), &(this->mutex
),&timeout
);
197 /* reset cancellation, remove mutex-unlock handler (without executing) */
198 pthread_setcancelstate(oldstate
, NULL
);
199 pthread_cleanup_pop(0);
203 /* event available */
204 this->list
->remove_first(this->list
,(void **) &next_event
);
206 job
= next_event
->job
;
208 next_event
->destroy(next_event
);
213 pthread_cond_signal( &(this->condvar
));
215 pthread_mutex_unlock(&(this->mutex
));
221 * Implements function add_absolute of event_queue_t.
222 * See #event_queue_s.add_absolute for description.
224 static void add_absolute(private_event_queue_t
*this, job_t
*job
, timeval_t time
)
226 event_t
*event
= event_create(time
,job
);
227 event_t
*current_event
;
230 pthread_mutex_lock(&(this->mutex
));
232 /* while just used to break out */
235 if (this->list
->get_count(this->list
) == 0)
237 this->list
->insert_first(this->list
,event
);
241 /* check last entry */
242 this->list
->get_last(this->list
,(void **) ¤t_event
);
244 if (time_difference(&(event
->time
), &(current_event
->time
)) >= 0)
246 /* my event has to be fired after the last event in list */
247 this->list
->insert_last(this->list
,event
);
251 /* check first entry */
252 this->list
->get_first(this->list
,(void **) ¤t_event
);
254 if (time_difference(&(event
->time
), &(current_event
->time
)) < 0)
256 /* my event has to be fired before the first event in list */
257 this->list
->insert_first(this->list
,event
);
261 iterator_t
* iterator
;
263 iterator
= this->list
->create_iterator(this->list
,TRUE
);
265 iterator
->has_next(iterator
);
266 /* first element has not to be checked (already done) */
268 while(iterator
->has_next(iterator
))
270 status
= iterator
->current(iterator
,(void **) ¤t_event
);
272 if (time_difference(&(event
->time
), &(current_event
->time
)) <= 0)
274 /* my event has to be fired before the current event in list */
275 iterator
->insert_before(iterator
,event
);
279 iterator
->destroy(iterator
);
283 pthread_cond_signal( &(this->condvar
));
284 pthread_mutex_unlock(&(this->mutex
));
288 * Implements event_queue_t.add_relative.
290 static void add_relative(event_queue_t
*this, job_t
*job
, u_int32_t ms
)
292 timeval_t current_time
;
294 int micros
= ms
* 1000;
296 gettimeofday(¤t_time
, NULL
);
298 time
.tv_usec
= ((current_time
.tv_usec
+ micros
) % 1000000);
299 time
.tv_sec
= current_time
.tv_sec
+ ((current_time
.tv_usec
+ micros
)/ 1000000);
301 this->add_absolute(this, job
, time
);
306 * Implements event_queue_t.destroy.
308 static void event_queue_destroy(private_event_queue_t
*this)
310 while (this->list
->get_count(this->list
) > 0)
314 if (this->list
->remove_first(this->list
,(void *) &event
) != SUCCESS
)
316 this->list
->destroy(this->list
);
319 event
->job
->destroy_all(event
->job
);
320 event
->destroy(event
);
322 this->list
->destroy(this->list
);
324 pthread_mutex_destroy(&(this->mutex
));
326 pthread_cond_destroy(&(this->condvar
));
332 * Documented in header
334 event_queue_t
*event_queue_create()
336 private_event_queue_t
*this = malloc_thing(private_event_queue_t
);
338 this->public.get_count
= (int (*) (event_queue_t
*event_queue
)) get_count
;
339 this->public.get
= (job_t
*(*) (event_queue_t
*event_queue
)) get
;
340 this->public.add_absolute
= (void (*) (event_queue_t
*event_queue
, job_t
*job
, timeval_t time
)) add_absolute
;
341 this->public.add_relative
= (void (*) (event_queue_t
*event_queue
, job_t
*job
, u_int32_t ms
)) add_relative
;
342 this->public.destroy
= (void (*) (event_queue_t
*event_queue
)) event_queue_destroy
;
344 this->list
= linked_list_create();
345 pthread_mutex_init(&(this->mutex
), NULL
);
346 pthread_cond_init(&(this->condvar
), NULL
);
348 return (&this->public);