4 * @brief Event-Queue based on linked_list_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
24 #include <pluto/constants.h>
25 #include <pluto/defs.h>
29 #include "allocator.h"
31 #include "event_queue.h"
32 #include "linked_list.h"
37 * @brief represents an event as it is stored in the event queue
39 * A event consists of a event time and an assigned job object
42 typedef struct event_s event_t
;
46 * Time to fire the event
51 * Every event has its assigned job
56 * @brief Destroys a event_t object
58 * @param event_t calling object
59 * @returns SUCCESS if succeeded, FAILED otherwise
61 status_t (*destroy
) (event_t
*event
);
66 * @brief implements function destroy of event_t
68 static status_t
event_destroy(event_t
*event
)
74 allocator_free(event
);
79 * @brief Creates a event for a specific time
81 * @param time to fire the event
82 * @param job job to add to job-queue at specific time
84 * @return event_t event object
86 static event_t
*event_create(timeval_t time
, job_t
*job
)
88 event_t
*this = allocator_alloc_thing(event_t
);
90 this->destroy
= event_destroy
;
100 * @brief Private Variables and Functions of event_queue class
103 typedef struct private_event_queue_s private_event_queue_t
;
106 struct private_event_queue_s
{
107 event_queue_t
public;
110 * The events are stored in a linked list
115 * access to linked_list is locked through this mutex
117 pthread_mutex_t mutex
;
120 * If the queue is empty or an event has not to be fired
121 * a thread has to wait
122 * This condvar is used to wake up such a thread
124 pthread_cond_t condvar
;
128 * Returns the difference of to timeval structs in microseconds
130 * @param end_time end time
131 * @param start_time start time
133 * @warning this function is also defined in the tester class
134 * In later improvements, this function can be added to a general
137 * @return difference in microseconds
139 static long time_difference(struct timeval
*end_time
, struct timeval
*start_time
)
141 long seconds
, microseconds
;
143 seconds
= (end_time
->tv_sec
- start_time
->tv_sec
);
144 microseconds
= (end_time
->tv_usec
- start_time
->tv_usec
);
145 return ((seconds
* 1000000) + microseconds
);
150 * @brief implements function get_count of event_queue_t
152 static status_t
get_count (private_event_queue_t
*this, int *count
)
154 pthread_mutex_lock(&(this->mutex
));
155 status_t status
= this->list
->get_count(this->list
,count
);
156 pthread_mutex_unlock(&(this->mutex
));
161 * @brief implements function get of event_queue_t
163 static status_t
get(private_event_queue_t
*this, job_t
**job
)
166 timeval_t current_time
;
167 event_t
* next_event
;
171 pthread_mutex_lock(&(this->mutex
));
175 this->list
->get_count(this->list
,&count
);
178 /* add mutex unlock handler for cancellation, enable cancellation */
179 pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock
, (void*)&(this->mutex
));
180 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, &oldstate
);
182 pthread_cond_wait( &(this->condvar
), &(this->mutex
));
184 /* reset cancellation, remove mutex-unlock handler (without executing) */
185 pthread_setcancelstate(oldstate
, NULL
);
186 pthread_cleanup_pop(0);
188 this->list
->get_count(this->list
,&count
);
191 this->list
->get_first(this->list
,(void **) &next_event
);
193 gettimeofday(¤t_time
,NULL
);
194 long difference
= time_difference(¤t_time
,&(next_event
->time
));
197 timeout
.tv_sec
= next_event
->time
.tv_sec
;
198 timeout
.tv_nsec
= next_event
->time
.tv_usec
* 1000;
200 pthread_cond_timedwait( &(this->condvar
), &(this->mutex
),&timeout
);
204 /* event available */
205 this->list
->remove_first(this->list
,(void **) &next_event
);
207 *job
= next_event
->job
;
209 next_event
->destroy(next_event
);
214 pthread_cond_signal( &(this->condvar
));
216 pthread_mutex_unlock(&(this->mutex
));
222 * @brief implements function add of event_queue_t
224 static status_t
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
;
235 pthread_mutex_lock(&(this->mutex
));
237 /* while just used to break out */
240 this->list
->get_count(this->list
,&count
);
243 status
= this->list
->insert_first(this->list
,event
);
247 /* check last entry */
248 this->list
->get_last(this->list
,(void **) ¤t_event
);
250 if (time_difference(&(event
->time
), &(current_event
->time
)) >= 0)
252 /* my event has to be fired after the last event in list */
253 status
= this->list
->insert_last(this->list
,event
);
257 /* check first entry */
258 this->list
->get_first(this->list
,(void **) ¤t_event
);
260 if (time_difference(&(event
->time
), &(current_event
->time
)) < 0)
262 /* my event has to be fired before the first event in list */
263 status
= this->list
->insert_first(this->list
,event
);
267 linked_list_iterator_t
* iterator
;
269 status
= this->list
->create_iterator(this->list
,&iterator
,TRUE
);
270 if (status
!= SUCCESS
)
276 iterator
->has_next(iterator
);
277 /* first element has not to be checked (already done) */
279 while(iterator
->has_next(iterator
))
281 status
= iterator
->current(iterator
,(void **) ¤t_event
);
283 if (time_difference(&(event
->time
), &(current_event
->time
)) <= 0)
285 /* my event has to be fired before the current event in list */
286 status
= this->list
->insert_before(this->list
,iterator
,event
);
290 iterator
->destroy(iterator
);
294 pthread_cond_signal( &(this->condvar
));
295 pthread_mutex_unlock(&(this->mutex
));
297 if (status
!= SUCCESS
)
299 event
->destroy(event
);
305 * @brief implements function add of event_queue_t
307 static status_t
add_relative(event_queue_t
*this, job_t
*job
, u_int32_t ms
)
309 timeval_t current_time
;
311 int micros
= ms
* 1000;
313 gettimeofday(¤t_time
, NULL
);
315 time
.tv_usec
= ((current_time
.tv_usec
+ micros
) % 1000000);
316 time
.tv_sec
= current_time
.tv_sec
+ ((current_time
.tv_usec
+ micros
)/ 1000000);
318 return this->add_absolute(this, job
, time
);
323 * @brief implements function destroy of event_queue_t
325 static status_t
event_queue_destroy(private_event_queue_t
*this)
328 this->list
->get_count(this->list
,&count
);
333 if (this->list
->remove_first(this->list
,(void *) &event
) != SUCCESS
)
335 this->list
->destroy(this->list
);
338 event
->job
->destroy(event
->job
);
339 event
->destroy(event
);
340 this->list
->get_count(this->list
,&count
);
342 this->list
->destroy(this->list
);
344 pthread_mutex_destroy(&(this->mutex
));
346 pthread_cond_destroy(&(this->condvar
));
348 allocator_free(this);
354 * Documented in header
356 event_queue_t
*event_queue_create()
358 linked_list_t
*linked_list
= linked_list_create();
359 if (linked_list
== NULL
)
364 private_event_queue_t
*this = allocator_alloc_thing(private_event_queue_t
);
367 linked_list
->destroy(linked_list
);
371 this->public.get_count
= (status_t (*) (event_queue_t
*event_queue
, int *count
)) get_count
;
372 this->public.get
= (status_t (*) (event_queue_t
*event_queue
, job_t
**job
)) get
;
373 this->public.add_absolute
= (status_t (*) (event_queue_t
*event_queue
, job_t
*job
, timeval_t time
)) add_absolute
;
374 this->public.add_relative
= (status_t (*) (event_queue_t
*event_queue
, job_t
*job
, u_int32_t ms
)) add_relative
;
375 this->public.destroy
= (status_t (*) (event_queue_t
*event_queue
)) event_queue_destroy
;
377 this->list
= linked_list
;
378 pthread_mutex_init(&(this->mutex
), NULL
);
379 pthread_cond_init(&(this->condvar
), NULL
);
381 return (&this->public);