Removed strayed code fragment
[strongswan.git] / src / charon / processing / processor.c
1 /*
2 * Copyright (C) 2005-2007 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * Hochschule fuer Technik Rapperswil
5 *
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>.
10 *
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
14 * for more details.
15 */
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <errno.h>
20
21 #include "processor.h"
22
23 #include <daemon.h>
24 #include <threading/thread.h>
25 #include <threading/condvar.h>
26 #include <threading/mutex.h>
27 #include <utils/linked_list.h>
28
29
30 typedef struct private_processor_t private_processor_t;
31
32 /**
33 * Private data of processor_t class.
34 */
35 struct private_processor_t {
36 /**
37 * Public processor_t interface.
38 */
39 processor_t public;
40
41 /**
42 * Number of running threads
43 */
44 u_int total_threads;
45
46 /**
47 * Desired number of threads
48 */
49 u_int desired_threads;
50
51 /**
52 * Number of threads waiting for work
53 */
54 u_int idle_threads;
55
56 /**
57 * All threads managed in the pool (including threads that have been
58 * cancelled, this allows to join them during destruction)
59 */
60 linked_list_t *threads;
61
62 /**
63 * The jobs are stored in a linked list
64 */
65 linked_list_t *list;
66
67 /**
68 * access to linked_list is locked through this mutex
69 */
70 mutex_t *mutex;
71
72 /**
73 * Condvar to wait for new jobs
74 */
75 condvar_t *job_added;
76
77 /**
78 * Condvar to wait for terminated threads
79 */
80 condvar_t *thread_terminated;
81 };
82
83 static void process_jobs(private_processor_t *this);
84
85 /**
86 * restart a terminated thread
87 */
88 static void restart(private_processor_t *this)
89 {
90 thread_t *thread;
91
92 DBG2(DBG_JOB, "terminated worker thread, ID: %u", thread_current_id());
93
94 /* respawn thread if required */
95 this->mutex->lock(this->mutex);
96 if (this->desired_threads < this->total_threads ||
97 (thread = thread_create((thread_main_t)process_jobs, this)) == NULL)
98 {
99 this->total_threads--;
100 this->thread_terminated->signal(this->thread_terminated);
101 }
102 else
103 {
104 this->threads->insert_last(this->threads, thread);
105 }
106 this->mutex->unlock(this->mutex);
107 }
108
109 /**
110 * Process queued jobs, called by the worker threads
111 */
112 static void process_jobs(private_processor_t *this)
113 {
114 /* worker threads are not cancellable by default */
115 thread_cancelability(FALSE);
116
117 DBG2(DBG_JOB, "started worker thread, ID: %u", thread_current_id());
118
119 this->mutex->lock(this->mutex);
120 while (this->desired_threads >= this->total_threads)
121 {
122 job_t *job;
123
124 if (this->list->get_count(this->list) == 0)
125 {
126 this->idle_threads++;
127 this->job_added->wait(this->job_added, this->mutex);
128 this->idle_threads--;
129 continue;
130 }
131 this->list->remove_first(this->list, (void**)&job);
132 this->mutex->unlock(this->mutex);
133 /* terminated threads are restarted, so we have a constant pool */
134 thread_cleanup_push((thread_cleanup_t)restart, this);
135 job->execute(job);
136 thread_cleanup_pop(FALSE);
137 this->mutex->lock(this->mutex);
138 }
139 this->mutex->unlock(this->mutex);
140 restart(this);
141 }
142
143 /**
144 * Implementation of processor_t.get_total_threads.
145 */
146 static u_int get_total_threads(private_processor_t *this)
147 {
148 u_int count;
149 this->mutex->lock(this->mutex);
150 count = this->total_threads;
151 this->mutex->unlock(this->mutex);
152 return count;
153 }
154
155 /**
156 * Implementation of processor_t.get_idle_threads.
157 */
158 static u_int get_idle_threads(private_processor_t *this)
159 {
160 u_int count;
161 this->mutex->lock(this->mutex);
162 count = this->idle_threads;
163 this->mutex->unlock(this->mutex);
164 return count;
165 }
166
167 /**
168 * implements processor_t.get_job_load
169 */
170 static u_int get_job_load(private_processor_t *this)
171 {
172 u_int load;
173 this->mutex->lock(this->mutex);
174 load = this->list->get_count(this->list);
175 this->mutex->unlock(this->mutex);
176 return load;
177 }
178
179 /**
180 * implements function processor_t.queue_job
181 */
182 static void queue_job(private_processor_t *this, job_t *job)
183 {
184 this->mutex->lock(this->mutex);
185 this->list->insert_last(this->list, job);
186 this->job_added->signal(this->job_added);
187 this->mutex->unlock(this->mutex);
188 }
189
190 /**
191 * Implementation of processor_t.set_threads.
192 */
193 static void set_threads(private_processor_t *this, u_int count)
194 {
195 this->mutex->lock(this->mutex);
196 if (count > this->total_threads)
197 { /* increase thread count */
198 int i;
199 thread_t *current;
200
201 this->desired_threads = count;
202 DBG1(DBG_JOB, "spawning %d worker threads", count - this->total_threads);
203 for (i = this->total_threads; i < count; i++)
204 {
205 current = thread_create((thread_main_t)process_jobs, this);
206 if (current)
207 {
208 this->threads->insert_last(this->threads, current);
209 this->total_threads++;
210 }
211 }
212 }
213 else if (count < this->total_threads)
214 { /* decrease thread count */
215 this->desired_threads = count;
216 }
217 this->job_added->broadcast(this->job_added);
218 this->mutex->unlock(this->mutex);
219 }
220
221 /**
222 * Implementation of processor_t.destroy.
223 */
224 static void destroy(private_processor_t *this)
225 {
226 thread_t *current;
227 set_threads(this, 0);
228 this->mutex->lock(this->mutex);
229 while (this->total_threads > 0)
230 {
231 this->job_added->broadcast(this->job_added);
232 this->thread_terminated->wait(this->thread_terminated, this->mutex);
233 }
234 while (this->threads->remove_first(this->threads,
235 (void**)&current) == SUCCESS)
236 {
237 current->join(current);
238 }
239 this->mutex->unlock(this->mutex);
240 this->thread_terminated->destroy(this->thread_terminated);
241 this->job_added->destroy(this->job_added);
242 this->mutex->destroy(this->mutex);
243 this->list->destroy_offset(this->list, offsetof(job_t, destroy));
244 this->threads->destroy(this->threads);
245 free(this);
246 }
247
248 /*
249 * Described in header.
250 */
251 processor_t *processor_create(size_t pool_size)
252 {
253 private_processor_t *this = malloc_thing(private_processor_t);
254
255 this->public.get_total_threads = (u_int(*)(processor_t*))get_total_threads;
256 this->public.get_idle_threads = (u_int(*)(processor_t*))get_idle_threads;
257 this->public.get_job_load = (u_int(*)(processor_t*))get_job_load;
258 this->public.queue_job = (void(*)(processor_t*, job_t*))queue_job;
259 this->public.set_threads = (void(*)(processor_t*, u_int))set_threads;
260 this->public.destroy = (void(*)(processor_t*))destroy;
261
262 this->list = linked_list_create();
263 this->threads = linked_list_create();
264 this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
265 this->job_added = condvar_create(CONDVAR_TYPE_DEFAULT);
266 this->thread_terminated = condvar_create(CONDVAR_TYPE_DEFAULT);
267 this->total_threads = 0;
268 this->desired_threads = 0;
269 this->idle_threads = 0;
270
271 return &this->public;
272 }
273