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 <embb/base/c/base.h>
28 #include <embb/mtapi/c/mtapi.h>
29
30 #include <embb/base/c/internal/unused.h>
31
32 #include <embb_mtapi_log.h>
33 #include <mtapi_status_t.h>
34 #include <embb_mtapi_node_t.h>
35 #include <embb_mtapi_group_t.h>
36 #include <embb_mtapi_task_t.h>
37 #include <embb_mtapi_job_t.h>
38 #include <embb_mtapi_scheduler_t.h>
39 #include <embb_mtapi_thread_context_t.h>
40 #include <embb_mtapi_task_context_t.h>
41 #include <embb_mtapi_pool_template-inl.h>
42
43
44 mtapi_group_hndl_t MTAPI_GROUP_NONE = { 0, EMBB_MTAPI_IDPOOL_INVALID_ID };
45
46
47 /* ---- POOL STORAGE FUNCTIONS --------------------------------------------- */
48
embb_mtapi_pool_implementation(group)49 embb_mtapi_pool_implementation(group)
50
51
52 /* ---- CLASS MEMBERS ------------------------------------------------------ */
53
54 void embb_mtapi_group_initialize(embb_mtapi_group_t * that) {
55 assert(MTAPI_NULL != that);
56
57 that->group_id = MTAPI_GROUP_ID_NONE;
58 embb_atomic_init_int(&that->deleted, MTAPI_FALSE);
59 embb_atomic_init_int(&that->num_tasks, 0);
60 embb_mtapi_task_queue_initialize(&that->queue);
61 }
62
embb_mtapi_group_finalize(embb_mtapi_group_t * that)63 void embb_mtapi_group_finalize(embb_mtapi_group_t * that) {
64 assert(MTAPI_NULL != that);
65
66 embb_atomic_store_int(&that->deleted, MTAPI_TRUE);
67 embb_atomic_destroy_int(&that->deleted);
68 embb_atomic_store_int(&that->num_tasks, 0);
69 embb_atomic_destroy_int(&that->num_tasks);
70 embb_mtapi_task_queue_finalize(&that->queue);
71 }
72
73
74 /* ---- INTERFACE FUNCTIONS ------------------------------------------------ */
75
mtapi_group_create(MTAPI_IN mtapi_group_id_t group_id,MTAPI_IN mtapi_group_attributes_t * attributes,MTAPI_OUT mtapi_status_t * status)76 mtapi_group_hndl_t mtapi_group_create(
77 MTAPI_IN mtapi_group_id_t group_id,
78 MTAPI_IN mtapi_group_attributes_t* attributes,
79 MTAPI_OUT mtapi_status_t* status) {
80 mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
81 embb_mtapi_node_t* node = embb_mtapi_node_get_instance();
82 mtapi_group_hndl_t group_hndl = { 0, EMBB_MTAPI_IDPOOL_INVALID_ID };
83 embb_mtapi_group_t* group = NULL;
84
85 embb_mtapi_log_trace("mtapi_group_create() called\n");
86
87 if (embb_mtapi_node_is_initialized()) {
88 group = embb_mtapi_group_pool_allocate(node->group_pool);
89 if (MTAPI_NULL != group) {
90 embb_mtapi_group_initialize(group);
91 group->group_id = group_id;
92 if (MTAPI_NULL != attributes) {
93 group->attributes = *attributes;
94 local_status = MTAPI_SUCCESS;
95 } else {
96 mtapi_groupattr_init(&group->attributes, &local_status);
97 }
98 if (MTAPI_SUCCESS == local_status) {
99 group_hndl = group->handle;
100 } else {
101 embb_mtapi_group_finalize(group);
102 embb_mtapi_group_pool_deallocate(node->group_pool, group);
103 }
104 } else {
105 local_status = MTAPI_ERR_GROUP_LIMIT;
106 }
107 } else {
108 embb_mtapi_log_error("mtapi not initialized\n");
109 local_status = MTAPI_ERR_NODE_NOTINIT;
110 }
111
112 mtapi_status_set(status, local_status);
113 return group_hndl;
114 }
115
mtapi_group_set_attribute(MTAPI_IN mtapi_group_hndl_t group,MTAPI_IN mtapi_uint_t attribute_num,MTAPI_OUT void * attribute,MTAPI_IN mtapi_size_t attribute_size,MTAPI_OUT mtapi_status_t * status)116 void mtapi_group_set_attribute(
117 MTAPI_IN mtapi_group_hndl_t group,
118 MTAPI_IN mtapi_uint_t attribute_num,
119 MTAPI_OUT void* attribute,
120 MTAPI_IN mtapi_size_t attribute_size,
121 MTAPI_OUT mtapi_status_t* status) {
122 mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
123 embb_mtapi_node_t* node = embb_mtapi_node_get_instance();
124 embb_mtapi_group_t* local_group;
125
126 embb_mtapi_log_trace("mtapi_group_set_attribute() called\n");
127
128 if (embb_mtapi_node_is_initialized()) {
129 if (embb_mtapi_group_pool_is_handle_valid(node->group_pool, group)) {
130 local_group = embb_mtapi_group_pool_get_storage_for_handle(
131 node->group_pool, group);
132 mtapi_groupattr_set(&local_group->attributes, attribute_num,
133 attribute, attribute_size, &local_status);
134 } else {
135 local_status = MTAPI_ERR_GROUP_INVALID;
136 }
137 } else {
138 embb_mtapi_log_error("mtapi not initialized\n");
139 local_status = MTAPI_ERR_NODE_NOTINIT;
140 }
141
142 mtapi_status_set(status, local_status);
143 }
144
mtapi_group_get_attribute(MTAPI_IN mtapi_group_hndl_t group,MTAPI_IN mtapi_uint_t attribute_num,MTAPI_OUT void * attribute,MTAPI_IN mtapi_size_t attribute_size,MTAPI_OUT mtapi_status_t * status)145 void mtapi_group_get_attribute(
146 MTAPI_IN mtapi_group_hndl_t group,
147 MTAPI_IN mtapi_uint_t attribute_num,
148 MTAPI_OUT void* attribute,
149 MTAPI_IN mtapi_size_t attribute_size,
150 MTAPI_OUT mtapi_status_t* status ) {
151 mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
152
153 EMBB_UNUSED(attribute_num);
154 EMBB_UNUSED(attribute_size);
155
156 embb_mtapi_log_trace("mtapi_group_get_attribute() called\n");
157
158 if (embb_mtapi_node_is_initialized()) {
159 embb_mtapi_node_t* node = embb_mtapi_node_get_instance();
160 if (embb_mtapi_group_pool_is_handle_valid(node->group_pool, group)) {
161 /* the following is not needed for now, since there are no attributes
162
163 embb_mtapi_group_t* local_group =
164 embb_mtapi_group_pool_get_storage_for_handle(
165 node->group_pool, group); */
166
167 if (MTAPI_NULL == attribute) {
168 local_status = MTAPI_ERR_PARAMETER;
169 } else {
170 /* switch is not needed for now, since there are no attributes
171 switch (attribute_num) {
172 default: */
173 local_status = MTAPI_ERR_ATTR_NUM;
174 /* break;
175 }*/
176 }
177 } else {
178 local_status = MTAPI_ERR_GROUP_INVALID;
179 }
180 } else {
181 embb_mtapi_log_error("mtapi not initialized\n");
182 local_status = MTAPI_ERR_NODE_NOTINIT;
183 }
184
185 mtapi_status_set(status, local_status);
186 }
187
mtapi_group_wait_all(MTAPI_IN mtapi_group_hndl_t group,MTAPI_IN mtapi_timeout_t timeout,MTAPI_OUT mtapi_status_t * status)188 void mtapi_group_wait_all(
189 MTAPI_IN mtapi_group_hndl_t group,
190 MTAPI_IN mtapi_timeout_t timeout,
191 MTAPI_OUT mtapi_status_t* status) {
192 mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
193
194 embb_mtapi_log_trace("mtapi_group_wait_all() called\n");
195
196 if (embb_mtapi_node_is_initialized()) {
197 embb_mtapi_node_t* node = embb_mtapi_node_get_instance();
198 if (embb_mtapi_group_pool_is_handle_valid(node->group_pool, group)) {
199 embb_mtapi_thread_context_t * context = NULL;
200 embb_mtapi_group_t* local_group =
201 embb_mtapi_group_pool_get_storage_for_handle(
202 node->group_pool, group);
203
204 embb_duration_t wait_duration;
205 embb_time_t start_time;
206 embb_time_t end_time;
207 if (MTAPI_INFINITE < timeout) {
208 embb_duration_set_milliseconds(
209 &wait_duration, (unsigned long long)timeout);
210 embb_time_now(&start_time);
211 embb_time_in(&end_time, &wait_duration);
212 }
213
214 /* find out on which thread we are */
215 context = embb_mtapi_scheduler_get_current_thread_context(
216 node->scheduler);
217
218 /* wait for all tasks to arrive in the queue */
219 local_status = MTAPI_SUCCESS;
220 while (embb_atomic_load_int(&local_group->num_tasks)) {
221 embb_mtapi_task_t* local_task;
222
223 if (MTAPI_INFINITE < timeout) {
224 embb_time_t current_time;
225 embb_time_now(¤t_time);
226 if (embb_time_compare(¤t_time, &start_time) < 0) {
227 /* time has moved backwards, maybe a wraparound or jitter
228 move end_time backward to avoid endeless loop */
229 start_time = current_time;
230 embb_time_in(&end_time, &wait_duration);
231 }
232 if (embb_time_compare(¤t_time, &end_time) > 0) {
233 /* timeout! */
234 local_status = MTAPI_TIMEOUT;
235 break;
236 }
237 }
238
239 /* fetch and delete all available tasks */
240 local_task = embb_mtapi_task_queue_pop_front(&local_group->queue);
241 while (MTAPI_NULL != local_task) {
242 if (MTAPI_SUCCESS != local_task->error_code) {
243 local_status = local_task->error_code;
244 }
245 embb_mtapi_task_delete(local_task, node->task_pool);
246 embb_atomic_fetch_and_add_int(&local_group->num_tasks, -1);
247
248 local_task = embb_mtapi_task_queue_pop_front(&local_group->queue);
249 }
250
251 /* do other work if applicable */
252 embb_mtapi_scheduler_execute_task_or_yield(
253 node->scheduler,
254 node,
255 context);
256 }
257 if (MTAPI_TIMEOUT != local_status) {
258 /* group becomes invalid, so delete it */
259 mtapi_group_delete(group, MTAPI_NULL);
260 }
261 } else {
262 local_status = MTAPI_ERR_GROUP_INVALID;
263 }
264 } else {
265 embb_mtapi_log_error("mtapi not initialized\n");
266 local_status = MTAPI_ERR_NODE_NOTINIT;
267 }
268
269 mtapi_status_set(status, local_status);
270 embb_mtapi_log_trace("mtapi_group_wait_all() returns\n");
271 }
272
mtapi_group_wait_any(MTAPI_IN mtapi_group_hndl_t group,MTAPI_OUT void ** result,MTAPI_IN mtapi_timeout_t timeout,MTAPI_OUT mtapi_status_t * status)273 void mtapi_group_wait_any(
274 MTAPI_IN mtapi_group_hndl_t group,
275 MTAPI_OUT void** result,
276 MTAPI_IN mtapi_timeout_t timeout,
277 MTAPI_OUT mtapi_status_t* status) {
278 mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
279 void* local_result = MTAPI_NULL;
280
281 embb_mtapi_log_trace("mtapi_group_wait_any() called\n");
282
283 if (embb_mtapi_node_is_initialized()) {
284 embb_mtapi_node_t* node = embb_mtapi_node_get_instance();
285 if (embb_mtapi_group_pool_is_handle_valid(node->group_pool, group)) {
286 embb_mtapi_group_t* local_group =
287 embb_mtapi_group_pool_get_storage_for_handle(
288 node->group_pool, group);
289
290 embb_mtapi_task_t* local_task;
291 /* are there any tasks left? */
292 if (0 == embb_atomic_load_int(&local_group->num_tasks)) {
293 /* group becomes invalid, so delete it */
294 mtapi_group_delete(group, &local_status);
295 local_status = MTAPI_GROUP_COMPLETED;
296 } else {
297 embb_mtapi_thread_context_t * context = NULL;
298
299 embb_duration_t wait_duration;
300 embb_time_t start_time;
301 embb_time_t end_time;
302 if (MTAPI_INFINITE < timeout) {
303 embb_duration_set_milliseconds(
304 &wait_duration, (unsigned long long)timeout);
305 embb_time_now(&start_time);
306 embb_time_in(&end_time, &wait_duration);
307 }
308
309 /* find out on which thread we are */
310 context = embb_mtapi_scheduler_get_current_thread_context(
311 node->scheduler);
312
313 /* wait for any task to arrive */
314 local_status = MTAPI_SUCCESS;
315 local_task = embb_mtapi_task_queue_pop_front(&local_group->queue);
316 while (MTAPI_NULL == local_task) {
317 if (MTAPI_INFINITE < timeout) {
318 embb_time_t current_time;
319 embb_time_now(¤t_time);
320 if (embb_time_compare(¤t_time, &start_time) < 0) {
321 /* time has moved backwards, maybe a wraparound or jitter
322 move end_time backward to avoid endeless loop */
323 start_time = current_time;
324 embb_time_in(&end_time, &wait_duration);
325 }
326 if (embb_time_compare(¤t_time, &end_time) > 0) {
327 /* timeout! */
328 local_status = MTAPI_TIMEOUT;
329 break;
330 }
331 }
332
333 /* do other work if applicable */
334 embb_mtapi_scheduler_execute_task_or_yield(
335 node->scheduler,
336 node,
337 context);
338
339 /* try to pop a task from the group queue */
340 local_task = embb_mtapi_task_queue_pop_front(&local_group->queue);
341 }
342 /* was there a timeout, or is there a result? */
343 if (MTAPI_NULL != local_task) {
344 local_result = local_task->result_buffer;
345
346 /* return error code set by the task */
347 local_status = local_task->error_code;
348
349 /* delete task */
350 embb_mtapi_task_delete(local_task, node->task_pool);
351 embb_atomic_fetch_and_add_int(&local_group->num_tasks, -1);
352 }
353 }
354 } else {
355 local_status = MTAPI_ERR_GROUP_INVALID;
356 }
357 } else {
358 embb_mtapi_log_error("mtapi not initialized\n");
359 local_status = MTAPI_ERR_NODE_NOTINIT;
360 }
361
362 /* store result */
363 if (MTAPI_NULL != result) {
364 *result = local_result;
365 }
366
367 mtapi_status_set(status, local_status);
368 embb_mtapi_log_trace("mtapi_group_wait_any() returns\n");
369 }
370
mtapi_group_delete(MTAPI_IN mtapi_group_hndl_t group,MTAPI_OUT mtapi_status_t * status)371 void mtapi_group_delete(
372 MTAPI_IN mtapi_group_hndl_t group,
373 MTAPI_OUT mtapi_status_t* status) {
374 mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
375
376 if (embb_mtapi_node_is_initialized()) {
377 embb_mtapi_node_t* node = embb_mtapi_node_get_instance();
378 if (embb_mtapi_group_pool_is_handle_valid(node->group_pool, group)) {
379 embb_mtapi_group_t* local_group =
380 embb_mtapi_group_pool_get_storage_for_handle(
381 node->group_pool, group);
382
383 if (embb_atomic_load_int(&local_group->deleted)) {
384 local_status = MTAPI_ERR_GROUP_INVALID;
385 } else {
386 embb_mtapi_group_finalize(local_group);
387 embb_mtapi_group_pool_deallocate(node->group_pool, local_group);
388 local_status = MTAPI_SUCCESS;
389 }
390 } else {
391 local_status = MTAPI_ERR_GROUP_INVALID;
392 }
393 } else {
394 local_status = MTAPI_ERR_NODE_NOTINIT;
395 }
396
397 mtapi_status_set(status, local_status);
398 }
399