2 * Copyright (C) 2005-2006 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 #include "scheduler.h"
26 #include <processing/processor.h>
27 #include <processing/jobs/callback_job.h>
28 #include <utils/mutex.h>
30 typedef struct event_t event_t
;
33 * Event containing a job and a schedule time
37 * Time to fire the event.
42 * Every event has its assigned job.
48 * destroy an event and its job
50 static void event_destroy(event_t
*event
)
52 event
->job
->destroy(event
->job
);
56 typedef struct private_scheduler_t private_scheduler_t
;
59 * Private data of a scheduler_t object.
61 struct private_scheduler_t
{
63 * Public part of a scheduler_t object.
73 * The jobs are scheduled in a list.
78 * Exclusive access to list
83 * Condvar to wait for next job.
89 * Returns the difference of two timeval structs in milliseconds
91 static long time_difference(timeval_t
*end
, timeval_t
*start
)
96 s
= end
->tv_sec
- start
->tv_sec
;
97 us
= end
->tv_usec
- start
->tv_usec
;
98 return (s
* 1000 + us
/1000);
102 * Get events from the queue and pass it to the processor
104 static job_requeue_t
schedule(private_scheduler_t
* this)
112 DBG2(DBG_JOB
, "waiting for next event...");
113 this->mutex
->lock(this->mutex
);
115 gettimeofday(&now
, NULL
);
117 if (this->list
->get_count(this->list
) > 0)
119 this->list
->get_first(this->list
, (void **)&event
);
120 difference
= time_difference(&now
, &event
->time
);
123 this->list
->remove_first(this->list
, (void **)&event
);
124 this->mutex
->unlock(this->mutex
);
125 DBG2(DBG_JOB
, "got event, queueing job for execution");
126 charon
->processor
->queue_job(charon
->processor
, event
->job
);
128 return JOB_REQUEUE_DIRECT
;
132 pthread_cleanup_push((void*)this->mutex
->unlock
, this->mutex
);
133 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, &oldstate
);
137 this->condvar
->timed_wait_abs(this->condvar
, this->mutex
, event
->time
);
141 this->condvar
->wait(this->condvar
, this->mutex
);
143 pthread_setcancelstate(oldstate
, NULL
);
144 pthread_cleanup_pop(TRUE
);
145 return JOB_REQUEUE_DIRECT
;
149 * Implements scheduler_t.get_job_load
151 static u_int
get_job_load(private_scheduler_t
*this)
154 this->mutex
->lock(this->mutex
);
155 count
= this->list
->get_count(this->list
);
156 this->mutex
->unlock(this->mutex
);
161 * Implements scheduler_t.schedule_job.
163 static void schedule_job(private_scheduler_t
*this, job_t
*job
, u_int32_t time
)
166 event_t
*event
, *current
;
167 iterator_t
*iterator
;
171 event
= malloc_thing(event_t
);
174 /* calculate absolute time */
176 us
= (time
- s
* 1000) * 1000;
177 gettimeofday(&now
, NULL
);
178 event
->time
.tv_usec
= (now
.tv_usec
+ us
) % 1000000;
179 event
->time
.tv_sec
= now
.tv_sec
+ (now
.tv_usec
+ us
)/1000000 + s
;
181 this->mutex
->lock(this->mutex
);
184 if (this->list
->get_count(this->list
) == 0)
186 this->list
->insert_first(this->list
,event
);
190 this->list
->get_last(this->list
, (void**)¤t
);
191 if (time_difference(&event
->time
, ¤t
->time
) >= 0)
192 { /* new event has to be fired after the last event in list */
193 this->list
->insert_last(this->list
, event
);
197 this->list
->get_first(this->list
, (void**)¤t
);
198 if (time_difference(&event
->time
, ¤t
->time
) < 0)
199 { /* new event has to be fired before the first event in list */
200 this->list
->insert_first(this->list
, event
);
204 iterator
= this->list
->create_iterator(this->list
, TRUE
);
205 /* first element has not to be checked (already done) */
206 iterator
->iterate(iterator
, (void**)¤t
);
207 while(iterator
->iterate(iterator
, (void**)¤t
))
209 if (time_difference(&event
->time
, ¤t
->time
) <= 0)
211 /* new event has to be fired before the current event in list */
212 iterator
->insert_before(iterator
, event
);
216 iterator
->destroy(iterator
);
219 this->condvar
->signal(this->condvar
);
220 this->mutex
->unlock(this->mutex
);
224 * Implementation of scheduler_t.destroy.
226 static void destroy(private_scheduler_t
*this)
228 this->job
->cancel(this->job
);
229 this->condvar
->destroy(this->condvar
);
230 this->mutex
->destroy(this->mutex
);
231 this->list
->destroy_function(this->list
, (void*)event_destroy
);
236 * Described in header.
238 scheduler_t
* scheduler_create()
240 private_scheduler_t
*this = malloc_thing(private_scheduler_t
);
242 this->public.get_job_load
= (u_int (*) (scheduler_t
*this)) get_job_load
;
243 this->public.schedule_job
= (void (*) (scheduler_t
*this, job_t
*job
, u_int32_t ms
)) schedule_job
;
244 this->public.destroy
= (void(*)(scheduler_t
*)) destroy
;
246 this->list
= linked_list_create();
247 this->mutex
= mutex_create(MUTEX_DEFAULT
);
248 this->condvar
= condvar_create(CONDVAR_DEFAULT
);
250 this->job
= callback_job_create((callback_job_cb_t
)schedule
, this, NULL
, NULL
);
251 charon
->processor
->queue_job(charon
->processor
, (job_t
*)this->job
);
253 return &this->public;