1 /*
2 * Copyright (c) 2014-2017, Siemens AG. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include <assert.h>
28
29 #include <embb/mtapi/c/mtapi.h>
30 #include <embb/base/c/duration.h>
31 #include <embb/base/c/time.h>
32
33 #include <embb_mtapi_job_t.h>
34 #include <embb_mtapi_log.h>
35 #include <mtapi_status_t.h>
36 #include <embb_mtapi_node_t.h>
37 #include <embb_mtapi_action_t.h>
38 #include <embb_mtapi_pool_template-inl.h>
39 #include <embb_mtapi_attr.h>
40 #include <embb_mtapi_scheduler_t.h>
41 #include <embb_mtapi_task_t.h>
42
43
44 /* ---- POOL STORAGE FUNCTIONS --------------------------------------------- */
45
embb_mtapi_pool_implementation(action)46 embb_mtapi_pool_implementation(action)
47
48
49 /* ---- CLASS MEMBERS ------------------------------------------------------ */
50
51 void embb_mtapi_action_initialize(embb_mtapi_action_t* that) {
52 assert(MTAPI_NULL != that);
53
54 that->action_function = NULL;
55 that->job_id = MTAPI_JOB_ID_INVALID;
56 that->domain_id = MTAPI_DOMAIN_ID_INVALID;
57 that->node_id = MTAPI_NODE_ID_INVALID;
58 that->enabled = MTAPI_FALSE;
59 that->node_local_data = NULL;
60 that->node_local_data_size = 0;
61 that->plugin_data = MTAPI_NULL;
62 embb_atomic_init_int(&that->num_tasks, 0);
63 }
64
embb_mtapi_action_finalize(embb_mtapi_action_t * that)65 void embb_mtapi_action_finalize(embb_mtapi_action_t* that) {
66 assert(MTAPI_NULL != that);
67
68 if (that->is_plugin_action) {
69 // TODO(mw): check status
70 that->plugin_action_finalize_function(that->handle, NULL);
71 }
72 that->action_function = NULL;
73 that->job_id = MTAPI_JOB_ID_INVALID;
74 that->domain_id = MTAPI_DOMAIN_ID_INVALID;
75 that->node_id = MTAPI_NODE_ID_INVALID;
76 that->enabled = MTAPI_FALSE;
77 that->node_local_data = NULL;
78 that->node_local_data_size = 0;
79 that->plugin_data = MTAPI_NULL;
80 embb_atomic_destroy_int(&that->num_tasks);
81 }
82
embb_mtapi_action_delete_visitor(embb_mtapi_task_t * task,void * user_data)83 static mtapi_boolean_t embb_mtapi_action_delete_visitor(
84 embb_mtapi_task_t * task,
85 void * user_data) {
86 embb_mtapi_action_t * action = (embb_mtapi_action_t*)user_data;
87
88 assert(MTAPI_NULL != action);
89 assert(MTAPI_NULL != task);
90
91 if (
92 task->action.id == action->handle.id &&
93 task->action.tag == action->handle.tag) {
94 /* task is scheduled and needs to be cancelled */
95 embb_mtapi_task_set_state(task, MTAPI_TASK_CANCELLED);
96 task->error_code = MTAPI_ERR_ACTION_DELETED;
97 }
98
99 /* do not remove task from queue */
100 return MTAPI_TRUE;
101 }
102
embb_mtapi_action_disable_visitor(embb_mtapi_task_t * task,void * user_data)103 static mtapi_boolean_t embb_mtapi_action_disable_visitor(
104 embb_mtapi_task_t * task,
105 void * user_data) {
106 embb_mtapi_action_t * action = (embb_mtapi_action_t*)user_data;
107
108 assert(MTAPI_NULL != action);
109 assert(MTAPI_NULL != task);
110
111 if (
112 task->action.id == action->handle.id &&
113 task->action.tag == action->handle.tag) {
114 /* task is scheduled and needs to be cancelled */
115 embb_mtapi_task_set_state(task, MTAPI_TASK_CANCELLED);
116 task->error_code = MTAPI_ERR_ACTION_DISABLED;
117 }
118
119 /* do not remove task from queue */
120 return MTAPI_TRUE;
121 }
122
123
124 /* ---- INTERFACE FUNCTIONS ------------------------------------------------ */
125
mtapi_action_create(MTAPI_IN mtapi_job_id_t job_id,MTAPI_IN mtapi_action_function_t action_function,MTAPI_IN void * node_local_data,MTAPI_IN mtapi_size_t node_local_data_size,MTAPI_IN mtapi_action_attributes_t * attributes,MTAPI_OUT mtapi_status_t * status)126 mtapi_action_hndl_t mtapi_action_create(
127 MTAPI_IN mtapi_job_id_t job_id,
128 MTAPI_IN mtapi_action_function_t action_function,
129 MTAPI_IN void* node_local_data,
130 MTAPI_IN mtapi_size_t node_local_data_size,
131 MTAPI_IN mtapi_action_attributes_t* attributes,
132 MTAPI_OUT mtapi_status_t* status) {
133 mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
134 mtapi_action_hndl_t action_handle = { 0, EMBB_MTAPI_IDPOOL_INVALID_ID };
135
136 embb_mtapi_log_trace("mtapi_action_create() called\n");
137
138 if (embb_mtapi_node_is_initialized()) {
139 embb_mtapi_node_t* node = embb_mtapi_node_get_instance();
140 /* check if job is valid */
141 if (embb_mtapi_job_is_id_valid(node, job_id)) {
142 embb_mtapi_job_t* job = embb_mtapi_job_get_storage_for_id(node, job_id);
143 embb_mtapi_action_t* new_action =
144 embb_mtapi_action_pool_allocate(node->action_pool);
145 if (MTAPI_NULL != new_action) {
146 new_action->domain_id = node->domain_id;
147 new_action->node_id = node->node_id;
148 new_action->job_id = job_id;
149 new_action->node_local_data = node_local_data;
150 new_action->node_local_data_size = node_local_data_size;
151 new_action->enabled = MTAPI_TRUE;
152 new_action->is_plugin_action = MTAPI_FALSE;
153 embb_atomic_init_int(&new_action->num_tasks, 0);
154
155 new_action->action_function = action_function;
156
157 /* set defaults if no attributes were given */
158 if (MTAPI_NULL != attributes) {
159 new_action->attributes = *attributes;
160 local_status = MTAPI_SUCCESS;
161 } else {
162 /* use the default */
163 mtapi_actionattr_init(&new_action->attributes, &local_status);
164 }
165
166 /* check if affinity is sane */
167 if (0 == new_action->attributes.affinity) {
168 local_status = MTAPI_ERR_PARAMETER;
169 }
170
171 if (MTAPI_SUCCESS == local_status) {
172 action_handle = new_action->handle;
173 embb_mtapi_job_add_action(job, new_action);
174 } else {
175 embb_mtapi_action_finalize(new_action);
176 embb_mtapi_action_pool_deallocate(node->action_pool, new_action);
177 }
178 } else {
179 /* no more space left in action pool */
180 local_status = MTAPI_ERR_ACTION_LIMIT;
181 }
182 } else {
183 local_status = MTAPI_ERR_JOB_INVALID;
184 }
185 } else {
186 embb_mtapi_log_error("mtapi not initialized\n");
187 local_status = MTAPI_ERR_NODE_NOTINIT;
188 }
189
190 mtapi_status_set(status, local_status);
191 return action_handle;
192 }
193
194
mtapi_action_set_attribute(MTAPI_IN mtapi_action_hndl_t action,MTAPI_IN mtapi_uint_t attribute_num,MTAPI_IN void * attribute,MTAPI_IN mtapi_size_t attribute_size,MTAPI_OUT mtapi_status_t * status)195 void mtapi_action_set_attribute(
196 MTAPI_IN mtapi_action_hndl_t action,
197 MTAPI_IN mtapi_uint_t attribute_num,
198 MTAPI_IN void* attribute,
199 MTAPI_IN mtapi_size_t attribute_size,
200 MTAPI_OUT mtapi_status_t* status) {
201 mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
202
203 embb_mtapi_log_trace("mtapi_action_set_attribute() called\n");
204
205 if (embb_mtapi_node_is_initialized()) {
206 embb_mtapi_node_t* node = embb_mtapi_node_get_instance();
207 if (embb_mtapi_action_pool_is_handle_valid(node->action_pool, action)) {
208 embb_mtapi_action_t* local_action =
209 embb_mtapi_action_pool_get_storage_for_handle(
210 node->action_pool, action);
211 mtapi_actionattr_set(
212 &local_action->attributes,
213 attribute_num,
214 attribute,
215 attribute_size,
216 &local_status);
217 } else {
218 local_status = MTAPI_ERR_ACTION_INVALID;
219 }
220 } else {
221 embb_mtapi_log_error("mtapi not initialized\n");
222 local_status = MTAPI_ERR_NODE_NOTINIT;
223 }
224
225 mtapi_status_set(status, local_status);
226 }
227
228
mtapi_action_get_attribute(MTAPI_IN mtapi_action_hndl_t action,MTAPI_IN mtapi_uint_t attribute_num,MTAPI_OUT void * attribute,MTAPI_IN mtapi_size_t attribute_size,MTAPI_OUT mtapi_status_t * status)229 void mtapi_action_get_attribute(
230 MTAPI_IN mtapi_action_hndl_t action,
231 MTAPI_IN mtapi_uint_t attribute_num,
232 MTAPI_OUT void* attribute,
233 MTAPI_IN mtapi_size_t attribute_size,
234 MTAPI_OUT mtapi_status_t* status) {
235 mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
236
237 embb_mtapi_log_trace("mtapi_action_get_attribute() called\n");
238
239 if (embb_mtapi_node_is_initialized()) {
240 embb_mtapi_node_t* node = embb_mtapi_node_get_instance();
241 if (embb_mtapi_action_pool_is_handle_valid(node->action_pool, action)) {
242 embb_mtapi_action_t* local_action =
243 embb_mtapi_action_pool_get_storage_for_handle(
244 node->action_pool, action);
245
246 if (MTAPI_NULL == attribute) {
247 local_status = MTAPI_ERR_PARAMETER;
248 } else {
249 switch (attribute_num) {
250 case MTAPI_ACTION_GLOBAL:
251 local_status = embb_mtapi_attr_get_mtapi_boolean_t(
252 &local_action->attributes.global, attribute, attribute_size);
253 break;
254
255 case MTAPI_ACTION_AFFINITY:
256 local_status = embb_mtapi_attr_get_mtapi_affinity_t(
257 &local_action->attributes.affinity, attribute, attribute_size);
258 break;
259
260 case MTAPI_ACTION_DOMAIN_SHARED:
261 local_status = embb_mtapi_attr_get_mtapi_boolean_t(
262 &local_action->attributes.domain_shared,
263 attribute,
264 attribute_size);
265 break;
266
267 default:
268 /* attribute unknown */
269 local_status = MTAPI_ERR_ATTR_NUM;
270 break;
271 }
272 }
273 } else {
274 local_status = MTAPI_ERR_ACTION_INVALID;
275 }
276 } else {
277 embb_mtapi_log_error("mtapi not initialized\n");
278 local_status = MTAPI_ERR_NODE_NOTINIT;
279 }
280
281 mtapi_status_set(status, local_status);
282 }
283
284
mtapi_action_delete(MTAPI_IN mtapi_action_hndl_t action,MTAPI_IN mtapi_timeout_t timeout,MTAPI_OUT mtapi_status_t * status)285 void mtapi_action_delete(
286 MTAPI_IN mtapi_action_hndl_t action,
287 MTAPI_IN mtapi_timeout_t timeout,
288 MTAPI_OUT mtapi_status_t* status) {
289 mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
290
291 embb_mtapi_log_trace("mtapi_action_delete() called\n");
292
293 if (embb_mtapi_node_is_initialized()) {
294 embb_mtapi_node_t* node = embb_mtapi_node_get_instance();
295 if (embb_mtapi_action_pool_is_handle_valid(node->action_pool, action)) {
296 embb_mtapi_action_t* local_action =
297 embb_mtapi_action_pool_get_storage_for_handle(
298 node->action_pool, action);
299
300 embb_mtapi_thread_context_t * context = NULL;
301
302 embb_duration_t wait_duration;
303 embb_time_t start_time;
304 embb_time_t end_time;
305 if (MTAPI_INFINITE < timeout) {
306 embb_duration_set_milliseconds(
307 &wait_duration, (unsigned long long)timeout);
308 embb_time_now(&start_time);
309 embb_time_in(&end_time, &wait_duration);
310 }
311
312 /* cancel all tasks */
313 embb_mtapi_scheduler_process_tasks(
314 node->scheduler, embb_mtapi_action_delete_visitor, local_action);
315
316 /* find out on which thread we are */
317 context = embb_mtapi_scheduler_get_current_thread_context(
318 node->scheduler);
319
320 local_status = MTAPI_SUCCESS;
321 while (embb_atomic_load_int(&local_action->num_tasks)) {
322 if (MTAPI_INFINITE < timeout) {
323 embb_time_t current_time;
324 embb_time_now(¤t_time);
325 if (embb_time_compare(¤t_time, &start_time) < 0) {
326 /* time has moved backwards, maybe a wraparound or jitter
327 move end_time backward to avoid endeless loop */
328 start_time = current_time;
329 embb_time_in(&end_time, &wait_duration);
330 }
331 if (embb_time_compare(¤t_time, &end_time) > 0) {
332 /* timeout! */
333 local_status = MTAPI_TIMEOUT;
334 break;
335 }
336 }
337
338 /* do other work if applicable */
339 embb_mtapi_scheduler_execute_task_or_yield(
340 node->scheduler,
341 node,
342 context);
343 }
344
345 if (MTAPI_SUCCESS == local_status) {
346 /* delete action */
347 if (embb_mtapi_job_is_id_valid(node, local_action->job_id)) {
348 embb_mtapi_job_t* local_job = embb_mtapi_job_get_storage_for_id(
349 node, local_action->job_id);
350 embb_mtapi_job_remove_action(local_job, local_action);
351 }
352 embb_mtapi_action_finalize(local_action);
353 embb_mtapi_action_pool_deallocate(node->action_pool, local_action);
354 }
355 } else {
356 local_status = MTAPI_ERR_ACTION_INVALID;
357 }
358 } else {
359 embb_mtapi_log_error("mtapi not initialized\n");
360 local_status = MTAPI_ERR_NODE_NOTINIT;
361 }
362
363 mtapi_status_set(status, local_status);
364 }
365
mtapi_action_disable(MTAPI_IN mtapi_action_hndl_t action,MTAPI_IN mtapi_timeout_t timeout,MTAPI_OUT mtapi_status_t * status)366 void mtapi_action_disable(
367 MTAPI_IN mtapi_action_hndl_t action,
368 MTAPI_IN mtapi_timeout_t timeout,
369 MTAPI_OUT mtapi_status_t* status) {
370 mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
371
372 embb_mtapi_log_trace("mtapi_action_disable() called\n");
373
374 if (embb_mtapi_node_is_initialized()) {
375 embb_mtapi_node_t* node = embb_mtapi_node_get_instance();
376 if (embb_mtapi_action_pool_is_handle_valid(node->action_pool, action)) {
377 embb_mtapi_action_t* local_action =
378 embb_mtapi_action_pool_get_storage_for_handle(
379 node->action_pool, action);
380 local_action->enabled = MTAPI_FALSE;
381
382 embb_mtapi_thread_context_t * context = NULL;
383
384 embb_duration_t wait_duration;
385 embb_time_t start_time;
386 embb_time_t end_time;
387 if (MTAPI_INFINITE < timeout) {
388 embb_duration_set_milliseconds(
389 &wait_duration, (unsigned long long)timeout);
390 embb_time_now(&start_time);
391 embb_time_in(&end_time, &wait_duration);
392 }
393
394 /* cancel all tasks */
395 embb_mtapi_scheduler_process_tasks(
396 node->scheduler, embb_mtapi_action_disable_visitor, local_action);
397
398 /* find out on which thread we are */
399 context = embb_mtapi_scheduler_get_current_thread_context(
400 node->scheduler);
401
402 local_status = MTAPI_SUCCESS;
403 while (embb_atomic_load_int(&local_action->num_tasks)) {
404 if (MTAPI_INFINITE < timeout) {
405 embb_time_t current_time;
406 embb_time_now(¤t_time);
407 if (embb_time_compare(¤t_time, &start_time) < 0) {
408 /* time has moved backwards, maybe a wraparound or jitter
409 move end_time backward to avoid endeless loop */
410 start_time = current_time;
411 embb_time_in(&end_time, &wait_duration);
412 }
413 if (embb_time_compare(¤t_time, &end_time) > 0) {
414 /* timeout! */
415 local_status = MTAPI_TIMEOUT;
416 break;
417 }
418 }
419
420 /* do other work if applicable */
421 embb_mtapi_scheduler_execute_task_or_yield(
422 node->scheduler,
423 node,
424 context);
425 }
426 } else {
427 local_status = MTAPI_ERR_ACTION_INVALID;
428 }
429 } else {
430 embb_mtapi_log_error("mtapi not initialized\n");
431 local_status = MTAPI_ERR_NODE_NOTINIT;
432 }
433
434 mtapi_status_set(status, local_status);
435 }
436
mtapi_action_enable(MTAPI_IN mtapi_action_hndl_t action,MTAPI_OUT mtapi_status_t * status)437 void mtapi_action_enable(
438 MTAPI_IN mtapi_action_hndl_t action,
439 MTAPI_OUT mtapi_status_t* status) {
440 mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
441
442 embb_mtapi_log_trace("mtapi_action_enable() called\n");
443
444 if (embb_mtapi_node_is_initialized()) {
445 embb_mtapi_node_t* node = embb_mtapi_node_get_instance();
446 if (embb_mtapi_action_pool_is_handle_valid(node->action_pool, action)) {
447 embb_mtapi_action_t* local_action =
448 embb_mtapi_action_pool_get_storage_for_handle(
449 node->action_pool, action);
450 local_action->enabled = MTAPI_TRUE;
451 local_status = MTAPI_SUCCESS;
452 } else {
453 local_status = MTAPI_ERR_ACTION_INVALID;
454 }
455 } else {
456 embb_mtapi_log_error("mtapi not initialized\n");
457 local_status = MTAPI_ERR_NODE_NOTINIT;
458 }
459
460 mtapi_status_set(status, local_status);
461 }
462