1 // -----------------------------------------------------------------------
2 // Copyright (C) 2006 - 2007 by the FRESCOR consortium:
4 // Universidad de Cantabria, SPAIN
5 // University of York, UK
6 // Scuola Superiore Sant'Anna, ITALY
7 // Kaiserslautern University, GERMANY
8 // Univ. Politecnica Valencia, SPAIN
9 // Czech Technical University in Prague, CZECH REPUBLIC
11 // Thales Communication S.A. FRANCE
12 // Visual Tools S.A. SPAIN
13 // Rapita Systems Ltd UK
16 // See http://www.frescor.org
18 // The FRESCOR project (FP6/2005/IST/5-034026) is funded
19 // in part by the European Union Sixth Framework Programme
20 // The European Union is not liable of any use that may be
23 // All rights reserved.
25 // Redistribution and use in source and binary forms, with or
26 // without modification, are permitted provided that the
27 // following conditions are met:
29 // * Redistributions of source code must retain the above
30 // copyright notice, this list of conditions and the
31 // following disclaimer.
32 // * Redistributions in binary form must reproduce the above
33 // copyright notice, this list of conditions and the
34 // following disclaimer in the documentation and/or other
35 // materials provided with the distribution.
36 // * Neither the name of FRESCOR nor the names of its
37 // contributors may be used to endorse or promote products
38 // derived from this software without specific prior
39 // written permission.
41 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
42 // CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
43 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
44 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
45 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
46 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
47 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
48 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
49 // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
50 // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
51 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
53 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
54 // POSSIBILITY OF SUCH DAMAGE.
55 // -----------------------------------------------------------------------
56 //fosa_threads_and_signals.c
57 //==============================================
58 // ******** ****** ******** **********
59 // **///// /** ** **////// /** /**
60 // ** /** ** /** /** /**
61 // ******* /** ** /********* /**********
62 // **//// /** ** ////////** /**//////**
63 // ** /** ** /** /** /**
64 // ** /** ** ******** /** /**
65 // // /******/ //////// // //
67 // FOSA(Frescor Operating System Adaptation layer)
68 //================================================
75 #include "frsh_configuration_parameters.h"
78 #include "fosa_ose_implementation_specific.h"
83 * General entrypoint used when creating a process with POSIX look alike
84 * entrypoint. Recieves a signal and calls function received in signal
85 * with arguments also received in signal.
87 static OS_PROCESS(fosa_ose_process_entrypoint)
89 static const SIGSELECT accepted_signal[]
90 = { 1 ,FOSA_OSE_STARTUP_SIGNAL };
91 union SIGNAL* sig = receive(accepted_signal);
94 case FOSA_OSE_STARTUP_SIGNAL:
96 fosa_ose_signal_startup_t *startsig
97 = (fosa_ose_signal_startup_t *)sig;
99 // Call FOSA entrypoint.
100 startsig->code( startsig->arg );
105 // Call error() for all unexpected signals.
106 error2(0xFFFFFFFE, (OSERRCODE)sig);
110 kill_proc(current_process());
114 * @defgroup threadandsignals Thread and Signals
117 * This module defines the functions that manipulate frsh_threads and
118 * frsh_signals inside FRSH implementation.
120 * Applications can refer to FRSH threads but they cannot create them
121 * directly, instead they must use frsh_thread_create*() which in turn
122 * use fosa_thread_create().
124 * For signals, we assume that the OS provides a direct mapping
125 * for frsh_signal_t and frsh_signal_info_t in the native interface.
132 /*************************
133 * Thread identification
134 *************************/
137 * fosa_thread_equal()
139 * Compare two thread identifiers to determine if they refer to the
143 bool fosa_thread_equal(frsh_thread_id_t t1, frsh_thread_id_t t2)
152 * Return the thread id of the calling thread
154 frsh_thread_id_t fosa_thread_self()
156 return current_process();
159 /*************************
160 * Thread creation and termination
161 *************************/
164 * fosa_thread_create()
166 * This function creates a new thread using the attributes specified
167 * in attr. If attr is NULL, default attributes are used. The new
168 * thread starts running immediately, executing the function specified
169 * by code, with an argument equal to arg. Upon successful return, the
170 * variable pointed to by tid will contain the identifier of the newly
171 * created thread. The set of signals that may be synchronously
172 * accepted is inherited from the parent thread.
174 * Returns 0 if successful; otherwise it returs a code error:
176 * EAGAIN: the system lacks the necessary resources to create a
177 * new thread or the maximum number of threads has been
180 * EINVAL: the value specified by attr is invalid (for instance,
181 * it has not been correctly initialized)
183 * EREJECT: the cretion of the thread was rejected by the frsh scheduler
184 * possibly because of incorrect attributes, or because the
185 * requested minimum capacity cannot be guaranteed
188 int fosa_thread_create
189 (frsh_thread_id_t *tid, const frsh_thread_attr_t *attr,
190 frsh_thread_code_t code, void * arg)
194 OSADDRESS stack_size;
195 fosa_ose_process_info_t* NewProcess =
196 (fosa_ose_process_info_t *)heap_alloc_shared(
197 sizeof(fosa_ose_process_info_t), __FILE__, __LINE__);
199 //Initialize new node for fosa_ose_processes list.
201 // If NULL, the lowest(!) OSE priority is used.
202 priority = FRSH_HIGHEST_THREAD_PRIORITY;
204 NewProcess->pid = 0; //Unknown at this stage.
205 NewProcess->app_scheduled = false;
206 NewProcess->appsched_param = NULL;
207 NewProcess->appsched_param_size = 0;
209 if ((attr->prio < fosa_get_priority_min()) ||
210 (attr->prio > fosa_get_priority_max())) {
213 priority = attr->prio;
214 stack_size = attr->stack_size;
215 NewProcess->pid = 0; //Unknown at this stage.
216 NewProcess->app_scheduled = attr->app_scheduled;
217 NewProcess->appsched_param = attr->appsched_param; //!............Kasst?
218 NewProcess->appsched_param_size = attr->appsched_param_size;
220 NewProcess->nr_of_micros = 0;
221 NewProcess->nr_of_ticks = 0;
223 //Add new first node in fosa_ose_processes list.
224 NewProcess->NextProcess = fosa_ose_processes;
225 fosa_ose_processes = NewProcess;
227 //Create process name
229 sprintf( name, "fosa_ose_%u", ++process_name_number );
231 (*tid) = create_process(
232 OS_PRI_PROC, // Process type.
234 fosa_ose_process_entrypoint,// Entrypoint.
235 stack_size, // Stacksize.
236 priority, // Priority.
238 0, // 0 = Part of callers block.
239 NULL, // No signal redirection.
243 fosa_ose_processes->pid = *tid;
245 //Make the scheduler to call the new_thread callback.
246 fosa_ose_send_event_to_scheduler(*tid, FOSA_OSE_NEW_THREAD_SIGNAL);
248 //Receive from scheduler if accepted or rejected.
249 SIGSELECT sel_reply[] = {2, FOSA_OSE_REJECT, FOSA_OSE_ACCEPT};
250 fosa_ose_event_signal_t *reply_sig;
251 reply_sig = (fosa_ose_event_signal_t *) receive(sel_reply);
252 if (reply_sig->sig_no != FOSA_OSE_ACCEPT) {
253 //event_sig->sig_no == FOSA_OSE_REJECT or something else.
254 fosa_ose_process_list_node_remove(0);
259 //New thread accepted
262 //Allocate, initialize and send signal with fosa entrypoint.
263 fosa_ose_signal_startup_t *entrypoint;
264 entrypoint = (fosa_ose_signal_startup_t *)
265 alloc(sizeof(fosa_ose_signal_startup_t),
266 FOSA_OSE_STARTUP_SIGNAL);
267 entrypoint->code = code;
268 entrypoint->arg = arg;
269 send((union SIGNAL **)&entrypoint, *tid);
276 * Note: no thread termination primitive is provided. The termination
277 * of a thread will be notifoed by the system to the FRSH scheduler
278 * through the scheduler API
282 /**************************************************
283 * Thread-specific data
284 * (extended with access from a different thread)
286 * Several data items (pointers) may be associated with each thread
287 * Each item is identified through a key, an integer value between 0
288 * and FOSA_MAX_KEYS-1. The caller is responsible of allocating and
289 * deallocating the memory area pointed to by the pointer
290 **************************************************/
295 * Create a new key for thread specific data.
297 * Prior to setting data in a key, we need ask the system to create
300 * @return 0 if successful \n
301 * FOSA_EINVAL If we already have reached the FOSA_MAX_KEYS limit.
302 * FOSA_ENOMEM If there are no enough memory resources to
305 int fosa_key_create(int *key) {
309 * This function should return a new int each time it is called. If
310 * destroy is called for a number that int is freed and can be
313 if (!fosa_ose_keys_initialized) {
314 memset(fosa_ose_keys_taken, false, sizeof(bool) * FOSA_MAX_KEYS);
315 fosa_ose_keys_initialized = true;
319 for (i = 0; i < FOSA_MAX_KEYS; i++) {
320 if (fosa_ose_keys_taken[i] == false) break;
323 if (i >= FOSA_MAX_KEYS) {
327 // First empty key found (number i).
328 fosa_ose_keys_taken[i] = true;
339 * This destroys the key and isables its use in the system
341 * @return 0 if successful \n
342 * FOSA_EINVAL The key is not initialised or is not in FOSA key range.
344 int fosa_key_destroy(int key) {
345 fosa_ose_keys_taken[key] = false;
350 * fosa_thread_set_specific_data()
352 * Set thread-specific data
354 * For the thread identified by tid, the thread-specifid data field
355 * identified by key will be set to the value specified by value
357 * Returns 0 if successful; otherwise, an error code is returned
358 * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
360 * Alternatively, in case of error the implementation is allowed to
361 * notify it to the system console and then terminate the FRSH
362 * implementation and dependant applications
364 int fosa_thread_set_specific_data
365 (int key, frsh_thread_id_t tid, const void * value)
368 (key > FOSA_MAX_KEYS-1)) {
373 sprintf(ose_key, "fosa_key_%u", key);
375 bool sucess = set_envp(tid, ose_key, (OSADDRESS) value);
377 if (sucess) return 0;
378 else return FOSA_EINVAL;
384 * fosa_thread_get_specific_data()
386 * Get thread-specific data
388 * For the thread identified by tid, the thread-specifid data field
389 * identified by key will be copied to the variable pointed to by value
391 * Returns 0 if successful; otherwise, an error code is returned
392 * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1
394 * Alternatively, in case of error the implementation is allowed to
395 * notify it to the system console and then terminate the FRSH
396 * implementation and dependant applications
398 int fosa_thread_get_specific_data(int key, frsh_thread_id_t tid,
402 (key > FOSA_MAX_KEYS-1)) {
407 sprintf( ose_key, "fosa_key_%u", key );
409 *value = (void*) get_envp(tid, ose_key);
415 /******************************************************************
418 * This implementation of FRSH assumes an underlying fixed priority
419 * scheduler with priorities in a range, with a minimum and a
420 * maximumm, a number of priority levels with at least 31
421 * priorities. A larger number implies a larger priority. In systems
422 * in which the underlying scheduler uses the opposite convention, a
423 * mapping is automatically provided by the OS adaptation layer.
424 *******************************************************************/
427 * fosa_get_priority_max()
429 * Return the maximum priority value used in this implementation
431 int fosa_get_priority_max()
433 return FRSH_HIGHEST_THREAD_PRIORITY;
435 // Priority values in OSE are 0 - 31, where 0 represents the highest
436 // priority and 31 the lowest.
439 * fosa_get_priority_min()
441 * Return the minimum priority value used in this implementation
443 int fosa_get_priority_min()
445 return FRSH_LOWEST_THREAD_PRIORITY;
447 // Priority values in OSE are 0 - 31, where 0 represents the highest
448 // priority and 31 the lowest.
451 * fosa_thread_attr_set_prio()
453 * Change the priority of a thread attributes object
455 * The priority of the thread attriutes object specified by attr is
456 * set to the value specified by prio. This function has no runtime
457 * effect on the priority, except when the attributes object is used
458 * to create a thread, when it will be created with the specified
461 * Returns 0 if successful, or the following error code:
462 * EINVAL: the specified priority value is not between the
463 * minimum and the maximum priorities defined in this
464 * FRSH implementation
465 * Alternatively, in case of error the implementation is allowed to
466 * notify it to the system console and then terminate the FRSH
467 * implementation and dependant applications
469 int fosa_thread_attr_set_prio(frsh_thread_attr_t *attr, int prio)
471 if ((prio < fosa_get_priority_min()) ||
472 (prio > fosa_get_priority_max())) {
476 //Make ose priority from fosa priority, and set attr.
477 attr->prio = (OSPRIORITY) fosa_get_priority_max()
478 + fosa_get_priority_min() - prio;
485 * fosa_thread_attr_get_prio()
487 * Get the priority from a thread attributes object
489 * This function sets the variable pointed to by prio to the
490 * priority stored in the thread attributes object attr.
494 int fosa_thread_attr_get_prio
495 (const frsh_thread_attr_t *attr, size_t *prio)
497 // Map OSE priority to FOSA priority.
498 *prio = fosa_get_priority_max() + fosa_get_priority_min()
505 * fosa_thread_set_prio()
507 * Dynamically change the priority of a thread
509 * The priority of the thread identified by tid is
510 * set to the value specified by prio.
512 * Returns 0 if successful, or the following error code:
513 * EINVAL: the specified priority value is not between the
514 * minimum and the maximum priorities defined in this
515 * FRSH implementation
516 * Alternatively, in case of error the implementation is allowed to
517 * notify it to the system console and then terminate the FRSH
518 * implementation and dependant applications
520 int fosa_thread_set_prio(frsh_thread_id_t tid, int prio)
522 if ((prio < fosa_get_priority_min()) ||
523 (prio > fosa_get_priority_max())) {
526 // Map FOSA priority to OSE priority.
527 OSPRIORITY new_ose_prio = (OSPRIORITY) fosa_get_priority_max()
528 + fosa_get_priority_min() - prio;
530 OSPRIORITY org_prio = get_pri(tid);
532 if (org_prio == new_ose_prio) return 0;
534 int new_prio = set_pri_for(tid, new_ose_prio);
535 if(new_prio == org_prio) {
543 * fosa_thread_get_prio()
545 * Dynamically get the priority of a thread
547 * This function sets the variable pointed to by prio to the
548 * priority of the thread identified by tid
552 int fosa_thread_get_prio (frsh_thread_id_t tid, int *prio)
554 OSPRIORITY ose_prio = get_pri(tid);
555 // Map OSE priority to FOSA priority.
556 *prio = fosa_get_priority_max() + fosa_get_priority_min()
563 /*******************************************************************
566 * Signals represent events that may be notified by the system, or
567 * sent explicitly by the application, and for which a thread may
568 * synchronously wait. Signals carry an associated piece of
569 * information (an integer or a pointer) and are queued until they are
570 * accepted. Signals are identified by an integer signal number (of
571 * the type frsh_signal_t) in the range FOSA_SIGNAL_MIN,
572 * FOSA_SIGNAL_MAX. This range is required to have at least <tbd>
574 *******************************************************************/
577 * fosa_set_accepted_signals()
579 * Establish the set of signals that may be synchronously accepted
580 * by the calling thread
582 * The function uses the array of signal numbers specified by set,
583 * which must be of size equal to size
585 * Returns 0 if successful; otherwise it returns an error code:
586 * EINVAL: the array contains one or more values which are not
587 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
590 * Alternatively, in case of error the implementation is allowed to
591 * notify it to the system console and then terminate the FRSH
592 * implementation and dependant applications
594 int fosa_set_accepted_signals(frsh_signal_t set[], int size)
599 * This function is not neccisary in OSE since set[] is used as an
600 * argument in the calls to fosa_signal_wait() and
601 * fosa_signal_timedwait() functions. Also decided to be empty in
602 * Barcelona meeting 2007-01-31.
609 * fosa_signal_queue()
613 * This function is used to explicitly send a signal with a specified
616 * The signal number specified by signal is sent together with the
617 * information specified by info, to the thread identified by
618 * receiver. In those implementations that do not support queueing a
619 * signal with information to a thread (such as POSIX), the signal may
620 * be sent to any thread that is waiting for this signal via
621 * fosa_signal_wait(). Portability can be ensured by having the receiver
622 * thread be the one who is waiting for the signal.
624 * Returns 0 if successful; otherwise it returns an error code:
625 * EINVAL: the signal specified by signal is not
626 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
628 * EAGAIN: no resources are available to queue the signal; the
629 * maximum number of queued signals has been reached, or a
630 * systemwide resource limit has been exceeded
632 * Alternatively, in case of error the implementation is allowed to
633 * notify it to the system console and then terminate the FRSH
634 * implementation and dependant applications
636 int fosa_signal_queue
637 (frsh_signal_t signal, frsh_signal_info_t info,
638 frsh_thread_id_t receiver)
640 if ((signal < FOSA_SIGNAL_MIN) || (signal > FOSA_SIGNAL_MAX)) {
644 fosa_ose_signal_t *ose_sig;
645 ose_sig = (fosa_ose_signal_t *)
646 alloc(sizeof(fosa_ose_signal_t), signal);
648 ose_sig->info = info;
649 send((union SIGNAL **)&ose_sig, receiver);
651 //Other errors taken care of by OSE.
657 * fosa_signal_queue_scheduler()
659 * Queue a signal destinated to the scheduler
661 * This is a special case of fosa_signal_queue() in which the
662 * destinator is the scheduler itself. It is needed by the service
663 * thread to notify the results to the scheduler.
665 * The problem with this case is that, depending on the implementation,
666 * this call would be translated to a true signal or to a scheduler
667 * notification message.
669 * Besides for the scheduler we don't have always a destinator
670 * thread_id needed in frsh_signal_queue for OSE.
672 * So the fosa implementation will solve this issue internally.
674 * Returns 0 if successful; otherwise it returns an error code:
675 * EINVAL: the signal specified by signal is not
676 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
678 * EAGAIN: no resources are available to queue the signal; the
679 * maximum number of queued signals has been reached, or a
680 * systemwide resource limit has been exceeded
682 * Alternatively, in case of error the implementation is allowed to
683 * notify it to the system console and then terminate the FRSH
684 * implementation and dependant applications
686 int fosa_signal_queue_scheduler(frsh_signal_t signal,
687 frsh_signal_info_t info) {
689 hunt("fosa_scheduler_process", 0, &scheduler, (union SIGNAL **) NULL);
690 if (scheduler == 0) return EINVAL;
692 return fosa_signal_queue(signal, info, scheduler);
701 * The function waits for the arrival of one of the signals in the
702 * array of signal numbers specified by set, which must be of size
703 * equal to size. If there is a signal already queued, the function
704 * returns immediately. If there is no signal of the specified set
705 * queued, the calling thread is suspended until a signal from that
706 * set arrives. Upon return, if signal_received is not NULL the number
707 * of the signal received is stored in the variable pointed to by
708 * signal_received; and if info is not NULL the associated information
709 * is stored in the variable pointed to by info.
711 * Returns 0 if successful; otherwise it returns an error code:
712 * EINVAL: the array contains one or more values which are not
713 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
716 * Alternatively, in case of error the implementation is allowed to
717 * notify it to the system console and then terminate the FRSH
718 * implementation and dependant applications
721 (frsh_signal_t set[], int size, frsh_signal_t *signal_received,
722 frsh_signal_info_t *info)
724 if (size < 0) return FOSA_EINVAL;
726 for (i = 0; i < size; ++i) {
727 if ((set[i] < FOSA_SIGNAL_MIN) ||
728 (set[i] > FOSA_SIGNAL_MAX)) {
732 // No check for signals before receiving is needed.
735 SIGSELECT sig_set[size+1];
737 for (i = 1; i < size+1; ++i)
738 sig_set[i] = set[i-1];
739 union SIGNAL *ose_sig_union;
740 ose_sig_union = receive(sig_set);
742 fosa_ose_signal_t *ose_sig =
743 (fosa_ose_signal_t *)ose_sig_union;
746 if( signal_received != NULL )
747 *signal_received = ose_sig->sig_no;
749 *info = ose_sig->info;
751 free_buf(&ose_sig_union);
758 * fosa_signal_timedwait()
760 * Timed wait for a signal
762 * This function behaves the same as fosa_signal_wait(), except that
763 * the suspension time is limited to the time interval specified in
764 * the timespec structure referenced by timeout.
766 * Returns 0 if successful; otherwise it returns an error code:
767 * EINVAL: the array contains one or more values which are not
768 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size
769 * is less than 0, or timeout is invalid
770 * EAGAIN: The timeout expired
772 * Alternatively, in case of the EINVAL error the implementation is
773 * allowed to notify it to the system console and then terminate the
774 * FRSH implementation and dependant applications
776 int fosa_signal_timedwait
777 (frsh_signal_t set[], int size, frsh_signal_t *signal_received,
778 frsh_signal_info_t *info, const struct timespec *timeout)
780 if (size < 0) return FOSA_EINVAL;
782 for (i = 0; i < size; ++i) {
783 if ((set[i] < FOSA_SIGNAL_MIN) ||
784 (set[i] > FOSA_SIGNAL_MAX)) {
788 // No check for signals before receiving is needed.
791 SIGSELECT sig_set[size+1];
793 for (i = 1; i < size+1; ++i)
794 sig_set[i] = set[i-1];
796 OSTIME millisec = timeout->tv_sec * 1000 + timeout->tv_nsec / 1000;
798 union SIGNAL *ose_sig_union;
799 ose_sig_union = receive_w_tmo(millisec, sig_set);
802 if(ose_sig_union == NIL) return FOSA_EAGAIN;
804 fosa_ose_signal_t *ose_sig =
805 (fosa_ose_signal_t *)ose_sig_union;
808 if( signal_received != NULL )
809 *signal_received = ose_sig->sig_no;
811 *info = ose_sig->info;
813 free_buf(&ose_sig_union);