ae2236a3eeef1c99fac2ffb38c0d29e8311868f5
[strongswan.git] / src / charon / processing / jobs / callback_job.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #include "callback_job.h"
19
20 #include <daemon.h>
21
22 typedef struct private_callback_job_t private_callback_job_t;
23
24 /**
25 * Private data of an callback_job_t Object.
26 */
27 struct private_callback_job_t {
28 /**
29 * Public callback_job_t interface.
30 */
31 callback_job_t public;
32
33 /**
34 * Callback to call on execution
35 */
36 callback_job_cb_t callback;
37
38 /**
39 * parameter to supply to callback
40 */
41 void *data;
42
43 /**
44 * cleanup function for data
45 */
46 callback_job_cleanup_t cleanup;
47
48 /**
49 * thread ID of the job, if running
50 */
51 pthread_t thread;
52
53 /**
54 * mutex to access jobs interna
55 */
56 pthread_mutex_t mutex;
57
58 /**
59 * condvar to synchronize thread startup/cancellation
60 */
61 pthread_cond_t condvar;
62
63 /**
64 * list of asociated child jobs
65 */
66 linked_list_t *children;
67
68 /**
69 * parent of this job, or NULL
70 */
71 private_callback_job_t *parent;
72 };
73
74 /**
75 * Implements job_t.destroy.
76 */
77 static void destroy(private_callback_job_t *this)
78 {
79 if (this->cleanup)
80 {
81 this->cleanup(this->data);
82 }
83 this->children->destroy(this->children);
84 free(this);
85 }
86
87 /**
88 * unregister a child from its parent, if any.
89 */
90 static void unregister(private_callback_job_t *this)
91 {
92 if (this->parent)
93 {
94 iterator_t *iterator;
95 private_callback_job_t *child;
96
97 pthread_mutex_lock(&this->parent->mutex);
98 iterator = this->parent->children->create_iterator(this->parent->children, TRUE);
99 while (iterator->iterate(iterator, (void**)&child))
100 {
101 if (child == this)
102 {
103 iterator->remove(iterator);
104 break;
105 }
106 }
107 iterator->destroy(iterator);
108 pthread_mutex_unlock(&this->parent->mutex);
109 }
110 }
111
112 /**
113 * Implementation of callback_job_t.cancel.
114 */
115 static void cancel(private_callback_job_t *this)
116 {
117 pthread_t thread;
118
119 pthread_mutex_lock(&this->mutex);
120 thread = this->thread;
121
122 /* terminate its children */
123 this->children->invoke_offset(this->children, offsetof(callback_job_t, cancel));
124 pthread_mutex_unlock(&this->mutex);
125
126 /* terminate thread */
127 if (thread)
128 {
129 pthread_cancel(thread);
130 pthread_join(thread, NULL);
131 }
132 }
133
134 /**
135 * Implementation of job_t.execute.
136 */
137 static void execute(private_callback_job_t *this)
138 {
139 bool cleanup = FALSE;
140
141 pthread_mutex_lock(&this->mutex);
142 this->thread = pthread_self();
143 pthread_cond_signal(&this->condvar);
144 pthread_mutex_unlock(&this->mutex);
145
146 pthread_cleanup_push((void*)destroy, this);
147 while (TRUE)
148 {
149 switch (this->callback(this->data))
150 {
151 case JOB_REQUEUE_DIRECT:
152 continue;
153 case JOB_REQUEUE_FAIR:
154 {
155 this->thread = 0;
156 charon->processor->queue_job(charon->processor,
157 &this->public.job_interface);
158 break;
159 }
160 case JOB_REQUEUE_NONE:
161 default:
162 {
163 this->thread = 0;
164 cleanup = TRUE;
165 break;
166 }
167 }
168 break;
169 }
170 unregister(this);
171 pthread_cleanup_pop(cleanup);
172 }
173
174 /*
175 * Described in header.
176 */
177 callback_job_t *callback_job_create(callback_job_cb_t cb, void *data,
178 callback_job_cleanup_t cleanup,
179 callback_job_t *parent)
180 {
181 private_callback_job_t *this = malloc_thing(private_callback_job_t);
182
183 /* interface functions */
184 this->public.job_interface.execute = (void (*) (job_t *)) execute;
185 this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
186 this->public.cancel = (void(*)(callback_job_t*))cancel;
187
188 /* private variables */
189 pthread_mutex_init(&this->mutex, NULL);
190 pthread_cond_init(&this->condvar, NULL);
191 this->callback = cb;
192 this->data = data;
193 this->cleanup = cleanup;
194 this->thread = 0;
195 this->children = linked_list_create();
196 this->parent = (private_callback_job_t*)parent;
197
198 /* register us at parent */
199 if (parent)
200 {
201 pthread_mutex_lock(&this->parent->mutex);
202 this->parent->children->insert_last(this->parent->children, this);
203 pthread_mutex_unlock(&this->parent->mutex);
204 }
205
206 return &this->public;
207 }
208