2 //synchobj_repo_t synchobj_repo; /* defined downward, after the type definition! */
5 * synchronization objects repository
7 * data structure and macro declaration for the handling of the repository
8 * of synchronization objects needed by the API implementation.
9 * It's used only in the core API module so no problem implementing it all
10 * in this file without affecting the header files in frsh/include with
11 * such an implementation specific and tighted issue
13 * Note that mutual exclusive access is implemented both for the repository
14 * as a whole and for each single element to maximize the achievable
15 * parallelism and concurrency execution of threads
17 * Note also the synchronization object (subsection of the core) API is
18 * implemented within this file, without any request to the service thread,
19 * and so all "remain" local to a single process!
24 typedef struct synchobj_repo_entry {
29 } synchobj_repo_entry_t;
31 typedef struct synchobj_repo {
32 synchobj_repo_entry_t repo[FRSH_MAX_N_SYNCH_OBJECTS];
37 synchobj_repo_t synchobj_repo; /* global variable */
39 /* macro and functions */
42 * access functions to the repository
44 * some simple macro which help keep synchobj_repo_t opaque
45 * for the sake of code cleanness
48 /* given the handle of a synchronization object returns its index into the
49 * repository (frsh_synchobj_handle_t remains opaque) */
50 #define synchobj_handle_2_ind(h) \
52 /* given the index of a synchronization object in the repository returns
53 * an handle to it (frsh_synchobj_handle_t remains opaque)*/
54 #define synchobj_ind_2_handle(i) \
56 /* given a handle of a synchronization object returns a pointer to
57 * its entry into the repository */
58 #define get_synchobj_entry(handle) \
59 ( & ( synchobj_repo.repo[synchobj_handle_2_ind(handle)] ) )
60 /* return a pointer to the synchronization object repository mutex */
61 #define get_synchobj_repo_mutex() \
62 ( & ( synchobj_repo.mutex ) )
63 /* gives the actual number of synchronization objects in the repository */
64 #define get_synchobj_number() \
65 ( synchobj_repo.synchobj_number )
68 * consistency and status checks
70 * common used checkings and tests about the access to the repository
71 * and the status of each entry
74 /* are we accessing the repository with a valid index value ? */
75 #define check_synchobj_repo_ind(ind) \
76 ( ( ind >= 0 && ind < FRSH_MAX_N_SYNCH_OBJECTS ) ? true: false )
77 /* is the repository entry (correctly accessed and) free ? */
78 #define check_synchobj_repo_entry_free(ind) \
79 ( ( (check_synchobj_repo_ind(ind)) && \
80 synchobj_repo.repo[ind].events == -1 ) ? true : false )
81 /* is the repository entry (correctly accessed and) non free ? */
82 #define check_synchobj_repo_entry_nonfree(ind) \
83 ( ( (check_synchobj_repo_ind(ind)) && \
84 synchobj_repo.repo[ind].events != -1 ) ? true : false )
87 * initialize the repository
89 * sets all entries to invalid (that is, free) and init
92 * possible return values:
94 * false (something wrong with the mutex)
96 static inline bool synchobj_repo_init()
100 if (fosa_mutex_init(&synchobj_repo.mutex, 0) != 0)
103 synchobj_repo.synchobj_number = 0;
104 for (i = 0; i < FRSH_MAX_N_SYNCH_OBJECTS; i++) {
105 synchobj_repo.repo[i].events = -1;
106 synchobj_repo.repo[i].queued = -1;
115 * adds an entry into the repository. If successful the index of the entry is
116 * returned in vres_ind.
118 * We suppose the caller where to place the new entry and "suggests" us a
119 * free repository entry in synchobj_ind. We then check if it's really free
120 * and, if yes, we add the entry right there.
121 * If, on the other way, the entry is not free we need to search the whole
122 * repository for a suitable place.
124 * possible return values:
125 * true (entry correctly added)
126 * false (entry not added, maybe no more room in the repository!)
128 static inline bool synchobj_repo_put(int *synchobj_ind)
134 /* lock the repository */
135 fosa_mutex_lock(&synchobj_repo.mutex);
136 /* try to place the new entry in the caller provided position (if any)
137 * and, only if it's not free, scan all the repository for
138 * a different and suitable place */
139 if (synchobj_ind != NULL &&
140 check_synchobj_repo_entry_free(*synchobj_ind % FRSH_MAX_N_SYNCH_OBJECTS))
141 i = *synchobj_ind % FRSH_MAX_N_SYNCH_OBJECTS;
144 while (i < FRSH_MAX_N_SYNCH_OBJECTS && !check_synchobj_repo_entry_free(i))
147 /* if we're sure it's valid and free we place the
148 * thread entry into the repository in position 'i' */
150 if (check_synchobj_repo_entry_free(i)) {
151 if (fosa_mutex_init(&synchobj_repo.repo[i].mutex, 0) != 0)
153 if (fosa_cond_init(&synchobj_repo.repo[i].sync) != 0)
155 synchobj_repo.repo[i].events = 0;
156 synchobj_repo.repo[i].queued = 0;
157 if (synchobj_ind != NULL)
162 /* unlock the repository */
163 fosa_mutex_unlock(&synchobj_repo.mutex);
171 * sets the entry as free (if it already is not) and decrement the counter
173 * possible return values:
174 * true (all ok, entry was non-free and is now free)
175 * false (something wrong, entry was already free or index is out of renge)
177 static inline bool synchobj_repo_free(const int synchobj_ind)
181 /* lock the whole repository */
182 fosa_mutex_lock(&synchobj_repo.mutex);
185 if (check_synchobj_repo_entry_nonfree(synchobj_ind)) {
186 fosa_mutex_destroy(&synchobj_repo.repo[synchobj_ind].mutex);
187 fosa_cond_destroy(&synchobj_repo.repo[synchobj_ind].sync);
188 synchobj_repo.repo[synchobj_ind].events = -1;
189 synchobj_repo.repo[synchobj_ind].queued = -1;
190 synchobj_repo.synchobj_number--;
194 /* unlock the whole repository */
195 fosa_mutex_unlock(&synchobj_repo.mutex);
203 * check if a specific entry of the repository can be considered free
204 * (we need do it with an atomic lock)
206 * possible return values:
207 * true (entry is free)
208 * false (entry is not free or index is out of range)
210 static inline bool synchobj_repo_isfree(const int synchobj_ind)
214 /* lock the repository */
215 fosa_mutex_lock(&synchobj_repo.mutex);
217 result = check_synchobj_repo_entry_free(synchobj_ind);
219 /* unlock the repository */
220 fosa_mutex_unlock(&synchobj_repo.mutex);
225 /////////////////////////////////////////////////
226 // S Y N C H R O N I Z A T I O N O B J E C T S
227 /////////////////////////////////////////////////
230 * This section is implemented much differently from how it's described
231 * in the docs since the synchronization object are not unusable from
232 * INDETERMINATE workload type thread (remember we actually we're
233 * only handling such a type of vres!!), but they simply provide, for them,
234 * a conditional [timed] wait/signal mechanism as available and implemented in
235 * many OSs and threading library.
237 * In INDETERMINATE workloads, of course, a wait request on an synchronization
238 * object (or a timed wait request) does not imply the end of the current job
239 * nor cause any budget to be "returned", since no jobs are defined for them.
241 * In BUONDED workloads, when they'll be implemented here, we can flawlessy
242 * realize the API docs' semantic and consider end-job signals and budget
245 * Note that, beside the peculiarity of this implementation being the
246 * orthogonality with respect to threads and processes, all the
247 * synchronization objects API section is implemented without bothering the
248 * service thread, so it remains local to the single process and usable from
249 * its various threads to synchronize themself, i.e. it is by no way usable in
250 * order to synchronize different processes or different threads among
251 * different processes between each other!
255 * frsh_synchobj_create(), create a synchronization object
257 * Note FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD and
258 * FRSH_ERR_INVALID_SCHEDULER_REPLY are never returned as errors within
259 * this implementation
261 * possible return values:
263 * FRSH_ERR_NOT_INITIALIZED
264 * FRSH_ERR_BAD_ARGUMENT (NULL synchronization object handle)
265 * FRSH_ERR_TOO_MANY_SYNCH_OBJECTS
266 * FRSH_ERR_INTERNAL_ERROR (something, different from previous, went wrong)
268 int frsh_synchobj_create(frsh_synchobj_handle_t *synch_handle)
273 strncpy(FUNCNAME, "frsh_synchobj_create", 21);
276 /* check for framework initialization and arguments */
277 if (!frsh_initialized)
278 PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
279 "can't proceed before initializing FRSH with 'frsh_init()'!");
280 if (synch_handle == NULL)
281 PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
282 "can't return a synchronization object in a NULL synch_handle");
284 /* add the object and return an handler to it */
285 if (synchobj_repo_put(&synch_ind))
286 *synch_handle = synchobj_ind_2_handle(synch_ind);
288 /* something wrong, try to guess what */
289 if (get_synchobj_number() >= FRSH_MAX_N_SYNCH_OBJECTS)
290 /* synchronization object max number reached */
291 PERROR_AND_RETURN(FRSH_ERR_TOO_MANY_SYNCH_OBJS,
292 "can't create any more synchronization objects");
294 /* unspecified error (this should almost never be reached) */
295 PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
296 "can't create the synchronization objects");
298 return FRSH_NO_ERROR;
302 * frsh_synchobj_destroy(), destroy a synchronization object
304 * Note we check if wakeing up some threads is needed and we do this while
305 * holding a lock on the synchronization object, acquired while holding
306 * a lock on the whole repository in order to prevent races
308 * Note FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD and
309 * FRSH_ERR_INVALID_SCHEDULER_REPLY are never returned as errors within
310 * this implementation too
312 * possible return value:
314 * FRSH_ERR_NOT_INITIALIZED
315 * FRSH_ERR_INVALID_SYNCH_OBJ_HANDLE
316 * FRSH_ERR_INTERNAL_ERROR (something, different from previous, went wrong)
318 int frsh_synchobj_destroy(const frsh_synchobj_handle_t synch_handle)
320 /* check for framework initialization and arguments */
321 if (!frsh_initialized)
322 PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
323 "can't proceed before initializing FRSH with 'frsh_init()'!");
324 if (synchobj_repo_isfree(synchobj_handle_2_ind(synch_handle)))
325 PERROR_AND_RETURN(FRSH_ERR_INVALID_SYNCH_OBJ_HANDLE,
326 "can't destroy a synchronization object from an invalid synch_handle");
328 /* get an exclusive access lock to the synchronization object
329 * while holding the exclusive access to the whole repository for the
330 * sake of safetyness */
331 fosa_mutex_lock(get_synchobj_repo_mutex());
332 fosa_mutex_lock(&(get_synchobj_entry(synch_handle)->mutex));
333 fosa_mutex_unlock(get_synchobj_repo_mutex());
334 /* have I got to wake up someone ?? */
335 while (get_synchobj_entry(synch_handle)->queued > 0) {
336 if (fosa_cond_signal(&(get_synchobj_entry(synch_handle)->sync)) != 0) {
337 fosa_mutex_unlock(&(get_synchobj_entry(synch_handle)->mutex));
338 fosa_mutex_unlock(get_synchobj_repo_mutex());
339 PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
340 "can't wake up blocked threads while destroying the synchronization object");
342 get_synchobj_entry(synch_handle)->queued--;
344 /* release the lock on the synchronization object */
345 fosa_mutex_unlock(&(get_synchobj_entry(synch_handle)->mutex));
347 /* remove the synchronization object from the repository */
348 if (!synchobj_repo_free(synchobj_handle_2_ind(synch_handle)))
349 /* unspecified error (this should almost never be reached) */
350 PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
351 "can't delete the synchronization objects");
353 return FRSH_NO_ERROR;
357 * frsh_synchobj_wait() and frsh_synchobj_wit_with_timeout
359 * They're very very much similar between each other so we choose to implement
360 * them using a single generic function with a few more parameters to
361 * discriminate the two behaviours, avoiding a lot of code replication
364 static int synchobj_wait(bool with_timeoout, /* forward declaration of the generic wait function */
365 const frsh_synchobj_handle_t synch_handle,
366 const struct timespec *abs_timeout,
368 struct timespec *next_budget,
369 struct timespec *next_period,
370 bool *was_deadline_missed,
371 bool *was_budget_overran);
374 * frsh_synchobj_wait(), stop the thread till signaled by another one
376 * Implements the standard behaviour of a wait for a condition to be verified
377 * and signaled by another thread of the process.
379 * As stated before is perfectly usable even by the INDETERMINATE workloads
380 * for whom it does not represent the 'end job' event.
382 * It's implemented simply by a call to the generic function coded below
384 * Note FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD and
385 * FRSH_ERR_INVALID_SCHEDULER_REPLY are never returned as errors within
386 * this implementation and also FRSH_ERR_WORKLOAD_NOT_COMPATIBLE
389 * possible return values:
391 * FRSH_ERR_NOT_INITIALIZED
392 * FRSH_ERR_INVALID_SYNCH_OBJ_HANDLE (invalid synch. object or too many thread queued on it)
393 * all that frsh_thread_get_vres_id returns (FRSH_ERR_NOT_BOUND, )
394 * FRSH_ERR_INTERNAL_ERROR (something wrong trying to wait on the object)
396 int frsh_synchobj_wait(const frsh_synchobj_handle_t synch_handle,
397 frsh_rel_time_t *next_budget,
398 frsh_rel_time_t *next_period,
399 bool *was_deadline_missed,
400 bool *was_budget_overran)
402 /* simply call the generic function asking for a wait without any timeout */
403 return synchobj_wait(false, synch_handle, NULL, NULL, next_budget, next_period,
404 was_deadline_missed, was_budget_overran);
408 * frsh_synchobj_wait_with_timeout(), stop the thread till a timeout or a signal by another one
410 * Implements the standard behaviour of a wait for a condition to be verified
411 * and signaled by another thread of the process with a max. timeout value
413 * It's exactly the same as 'frsh_synchobj_wait()' with the only difference of
414 * the timeout and so it's, again, implemented simply by a call to the generic
415 * function with the correct parameters
417 * Note FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD and
418 * FRSH_ERR_INVALID_SCHEDULER_REPLY are never returned as errors within
419 * this implementation and also FRSH_ERR_WORKLOAD_NOT_COMPATIBLE
422 * possible return values:
424 * FRSH_ERR_NOT_INITIALIZED
425 * FRSH_ERR_INVALID_SYNCH_OBJ_HANDLE (invalid synch. object or too many thread queued on it)
426 * all that 'frsh_thread_get_vres_id()' returns (FRSH_ERR_NOT_BOUND, )
427 * FRSH_ERR_INTERNAL_ERROR (something wrong trying to wait on the object)
429 int frsh_synchobj_wait_with_timeout(
430 const frsh_synchobj_handle_t synch_handle,
431 const frsh_abs_time_t *abs_timeout,
433 frsh_rel_time_t *next_budget,
434 frsh_rel_time_t *next_period,
435 bool *was_deadline_missed,
436 bool *was_budget_overran)
438 /* simply call the generic function asking for a wait with the specified timeout */
439 return synchobj_wait(true, synch_handle, abs_timeout, timed_out, next_budget, next_period,
440 was_deadline_missed, was_budget_overran);
444 * generic function definition:
445 * it _really_ implements both (depending on the parameters)
446 * wait on synchronization objects API calls
448 static int synchobj_wait(bool with_timeout, /* discriminating parameter between the two functions */
449 const frsh_synchobj_handle_t synch_handle,
450 const struct timespec *abs_timeout,
452 struct timespec *next_budget,
453 struct timespec *next_period,
454 bool *was_deadline_missed,
455 bool *was_budget_overran)
457 frsh_thread_id_t thread_self;
458 qres_sid_t thread_sid;
459 qres_time_t qres_thread_budget;
460 struct timespec tmp_thread_budget, tmp_thread_period;
461 frsh_vres_id_t vres_id;
462 int frsh_status, timedwait_status;
464 /* check for framework initialization and arguments */
465 if (!frsh_initialized)
466 PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
467 "can't proceed before initializing FRSH with 'frsh_init()'!");
468 /* check the thread is running with a negotiated contract */
469 thread_self = fosa_thread_self();
470 thread_sid = FRSH_QRES_NOT_VALID_SID;
471 vres_id = FRSH_NOT_VALID_VRES_ID;
472 /* ask AQuoSA directly, if it's succesfull we can avoid a call to
473 * the service thread that is much less overhead!! */
474 if (qres_get_sid(thread_self.linux_pid, thread_self.linux_tid, &thread_sid) == QOS_E_NOSERVER)
475 /* maybe we're bounded to a background vres and, in order
476 * of being sure, we need to ask the service thread :-( */
477 if ( (frsh_status = frsh_thread_get_vres_id(thread_self, &vres_id)) != FRSH_NO_ERROR)
478 PERROR_AND_RETURN(frsh_status,
479 "can't wait if the thread is not bound to any vres");
480 if (synchobj_repo_isfree(synchobj_handle_2_ind(synch_handle)))
481 PERROR_AND_RETURN(FRSH_ERR_INVALID_SYNCH_OBJ_HANDLE,
482 "can't wait on an synchronization object via an invalid synch_handler");
484 /* acquire the exclusive access lock on the synchronization object
485 * while holding it on the whole repository */
486 fosa_mutex_lock(get_synchobj_repo_mutex());
487 fosa_mutex_lock(&(get_synchobj_entry(synch_handle)->mutex));
488 fosa_mutex_unlock(get_synchobj_repo_mutex());
490 /* check if we can wait on the object or the limit has already been reached */
491 if ((get_synchobj_entry(synch_handle)->events == 0) &&
492 (get_synchobj_entry(synch_handle)->queued >= FRSH_MAX_N_VRES_IN_SYNCH_OBJECT)) {
493 fosa_mutex_unlock(&(get_synchobj_entry(synch_handle)->mutex));
494 PERROR_AND_RETURN(FRSH_ERR_INVALID_SYNCH_OBJ_HANDLE,
495 "can't queue more vres on this synchronization object");
497 /* we need to wait only if there are no ready events */
498 if (!get_synchobj_entry(synch_handle)->events) {
499 /* inform we're going to suspend oursef! */
500 get_synchobj_entry(synch_handle)->queued++;
503 timedwait_status = fosa_cond_timedwait(&(get_synchobj_entry(synch_handle)->sync),
504 &(get_synchobj_entry(synch_handle)->mutex),
506 if (timedwait_status != 0) {
507 if (timedwait_status == ETIMEDOUT) {
508 /* no signal event before the timeout */
510 get_synchobj_entry(synch_handle)->events++; /* preventive increment */
512 /* some other strange error! */
513 fosa_mutex_unlock(&(get_synchobj_entry(synch_handle)->mutex));
514 PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
515 "can't wait on the synchronization object");
519 if (fosa_cond_wait(&(get_synchobj_entry(synch_handle)->sync),
520 &(get_synchobj_entry(synch_handle)->mutex)) != 0) {
521 fosa_mutex_unlock(&(get_synchobj_entry(synch_handle)->mutex));
522 PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
523 "can't wait on the syncrhonization object");
525 /* the synchronization object is still valid? */
526 if (synchobj_repo_isfree(synchobj_handle_2_ind(synch_handle)))
527 /* no, someone destroyed our synchronization object! */
528 PERROR_AND_RETURN(FRSH_ERR_INVALID_SYNCH_OBJ_HANDLE,
529 "synchronization object no longer valid, it has been destroyed during wait");
530 get_synchobj_entry(synch_handle)->queued--;
532 get_synchobj_entry(synch_handle)->events--;
533 /* all done, release the lock on the synchronization object */
534 fosa_mutex_unlock(&(get_synchobj_entry(synch_handle)->mutex));
536 /* now retreive timing (budget and period) parameters, don't care about
537 * overruns (remember we're always WT_INDETERMINATE) and make them
539 if (next_period != NULL || (next_budget != NULL && thread_sid == -1)) {
540 /* ask the service thread only if it's strictly necessary !! */
541 if (vres_id == FRSH_NOT_VALID_VRES_ID)
542 /* we need to know (from the service thread) the vres_id */
543 if ( (frsh_status = frsh_thread_get_vres_id(thread_self, &vres_id)) != FRSH_NO_ERROR)
544 PERROR_AND_RETURN(frsh_status,
545 "can't gather vres info for period and budget retrieval");
546 if (frsh_vres_get_budget_and_period(vres_id,
548 &tmp_thread_period) != FRSH_NO_ERROR)
549 PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
550 "can't get vres/contract budget and period");
552 if (next_budget != NULL) {
553 if (thread_sid == FRSH_QRES_NOT_VALID_SID)
554 /* background thread, we use the contracted budget
555 * retrieved previously */
556 *next_budget = tmp_thread_budget;
558 /* regular thread, ask for the actual budget direclty to AQuoSA
559 * (much less overhead !!) */
560 if (qres_get_curr_budget(thread_sid, &qres_thread_budget) != QOS_OK)
561 PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
562 "can't get the actual budget for the vres");
563 usec_to_timespec(*next_budget, qres_thread_budget);
566 if (next_period != NULL)
567 *next_period = tmp_thread_period;
568 if (was_deadline_missed != NULL)
569 was_deadline_missed = false;
570 if (was_budget_overran != NULL)
571 was_budget_overran = false;
573 return FRSH_NO_ERROR;
577 * frsh_synchobj_signal(), notify a synchronization object
579 * Remember if noone is waiting for the notification it is queued in the
580 * synchronization objects
582 * Note FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD and
583 * FRSH_ERR_INVALID_SCHEDULER_REPLY are never returned as errors within
584 * this implementation too
586 * possible return values:
588 * FRSH_ERR_NOT_INITIALIZED
589 * FRSH_ERR_BAD_ARGUMENT (invalid synch_handle)
590 * FRSH_ERR_TOO_MANY_EVENTS_IN_SYNCH_OBJ
592 int frsh_synchobj_signal(const frsh_synchobj_handle_t synch_handle)
594 /* check for framework initialization and arguments */
595 if (!frsh_initialized)
596 PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
597 "can't proceed before initializing FRSH with 'frsh_init()'!");
598 if (synchobj_repo_isfree(synchobj_handle_2_ind(synch_handle)))
599 PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
600 "can't signal a synchronization object via an invalid synch_handle");
601 /* acquire the exclusive access lock on the synchronization object
602 * while holding it on the whole repository */
603 fosa_mutex_lock(get_synchobj_repo_mutex());
604 fosa_mutex_lock(&(get_synchobj_entry(synch_handle)->mutex));
605 fosa_mutex_unlock(get_synchobj_repo_mutex());
607 if (get_synchobj_entry(synch_handle)->events >= FRSH_MAX_N_EVENTS_IN_SYNCH_OBJECT) {
608 fosa_mutex_unlock(&(get_synchobj_entry(synch_handle)->mutex));
609 PERROR_AND_RETURN(FRSH_ERR_TOO_MANY_EVENTS_IN_SYNCH_OBJ,
610 "can't enqueue more events on the synchronization object");
612 get_synchobj_entry(synch_handle)->events++;
614 /* release the lock */
615 fosa_mutex_unlock(&(get_synchobj_entry(synch_handle)->mutex));
616 /* and, finally, signal the condition */
617 fosa_cond_signal(&(get_synchobj_entry(synch_handle)->sync));
619 return FRSH_NO_ERROR;
623 * frsh_timed_wait(), sleep until specified absolute time
625 * Again, it does not imply 'end job' or any budget modification for
626 * INDETERMINATE workload vres, simply wait for the timer to fire!
628 * The timeout is implemented via the 'clock_nanosleep()' function
629 * (we need to consider a fosa wrapper for it too) in order to get rid
630 * of all the problems related to signal handling in a multithreaded
631 * environment (and even because it's the simplest and best suited
632 * solution for the acheiving what we need to!!)
634 * possible return values:
636 * FRSH_ERR_NOT_INITIALIZED
637 * FRSH_ERR_BAD_ARGUMENT (NULL abs_time)
638 * FRSH_ERR_INTERNAL_ERROR (FRSH_ERR_TIME_SPEC_IN_THE_PAST)
639 * FRSH_ERR_INTERNAL_ERROR (something wrong with timer and/or signal handling)
640 * all that 'frsh_thread_get_vres_id()' returns (FRSH_ERR_NOT_BOUND, )
643 int frsh_timed_wait (
644 const frsh_abs_time_t *abs_time,
645 frsh_rel_time_t *next_budget,
646 frsh_rel_time_t *next_period,
647 bool *was_deadline_missed,
648 bool *was_budget_overran)
650 frsh_thread_id_t thread_self;
651 qres_sid_t thread_sid;
652 qres_time_t qres_thread_budget;
653 struct timespec tmp_thread_budget, tmp_thread_period;
654 frsh_vres_id_t vres_id;
655 frsh_abs_time_t actual_time, rm_time;
658 /* check for framework initialization and arguments */
659 if (!frsh_initialized)
660 PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
661 "can't proceed before initializing FRSH with 'frsh_init()'!");
662 if (abs_time == NULL)
663 PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
664 "can't wait for a NULL abs_time");
665 /* check the thread is running with a negotiated contract */
666 thread_self = fosa_thread_self();
667 thread_sid = FRSH_QRES_NOT_VALID_SID;
668 vres_id = FRSH_NOT_VALID_VRES_ID;
669 if (qres_get_sid(thread_self.linux_pid, thread_self.linux_tid, &thread_sid) == QOS_E_NOSERVER)
670 /* maybe we're bounded to a background vres and, in order
671 * of being sure, we need to ask the service thread :-( */
672 if ( (frsh_status = frsh_thread_get_vres_id(thread_self, &vres_id)) != FRSH_NO_ERROR)
673 PERROR_AND_RETURN(frsh_status,
674 "can't get the vres id the calling thread is associated with");
675 /* check the provided absolute time reference is in the future */
676 if (fosa_clock_get_time(FOSA_CLOCK_REALTIME, &actual_time) < 0)
677 PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
678 "can't get the current time");
679 if (frsh_abs_time_smaller(*abs_time, actual_time))
680 //PERROR_AND_RETURN(FRSH_ERR_TIME_SPEC_IN_THE_PAST,
681 PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
682 "can't wait for a past absolute time");
683 /* put the thread to sleep for the requested interval */
684 if (clock_nanosleep(FOSA_CLOCK_REALTIME, TIMER_ABSTIME, abs_time, &rm_time) < 0)
685 PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
686 "can't put the thread to sleep");
687 /* if ( <check, via rm_time, if we've been interrupted> )
690 /* retreive timing (budget and period) parameters, don't care about
691 * overruns (remember we're always WT_INDETERMINATE) and make them
693 if (next_period != NULL || (next_budget != NULL && thread_sid == FRSH_QRES_NOT_VALID_SID)) {
694 /* ask the service thread only if it's strictly necessary !! */
695 if (vres_id == FRSH_NOT_VALID_VRES_ID)
696 /* we need to know (from the service thread) the vres_id !! */
697 if ( (frsh_status = frsh_thread_get_vres_id(thread_self, &vres_id)) != FRSH_NO_ERROR)
698 PERROR_AND_RETURN(frsh_status,
699 "can't gather vres info for period and budget retrieval");
700 if (frsh_vres_get_budget_and_period(vres_id,
702 &tmp_thread_period) != FRSH_NO_ERROR)
703 PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
704 "can't get vres/contract budget and period");
706 if (next_budget != NULL) {
707 if (thread_sid == FRSH_QRES_NOT_VALID_SID)
708 /* background thread, we use the contracted budget
709 * retrieved previously */
710 *next_budget = tmp_thread_budget;
712 /* regular thread, ask for the actual budget direclty to AQuoSA
713 * (much less overhead !!) */
714 if (qres_get_curr_budget(thread_sid, &qres_thread_budget) != QOS_OK)
715 PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
716 "can't get the actual budget for the vres");
717 usec_to_timespec(*next_budget, qres_thread_budget);
720 if (next_period != NULL)
721 *next_period = tmp_thread_period;
722 if (was_deadline_missed != NULL)
723 *was_deadline_missed = false;
724 if (was_budget_overran != NULL)
725 *was_budget_overran = false;
727 return FRSH_NO_ERROR;