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
24 // based on previous work (FSF) done in the FIRST project
26 // Copyright (C) 2005 Mälardalen University, SWEDEN
27 // Scuola Superiore S.Anna, ITALY
28 // Universidad de Cantabria, SPAIN
29 // University of York, UK
31 // This file is part of FOSA (Frsh Operating System Abstraction)
33 // FOSA is free software; you can redistribute it and/or modify it
34 // under terms of the GNU General Public License as published by the
35 // Free Software Foundation; either version 2, or (at your option) any
36 // later version. FOSA is distributed in the hope that it will be
37 // useful, but WITHOUT ANY WARRANTY; without even the implied warranty
38 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
39 // General Public License for more details. You should have received a
40 // copy of the GNU General Public License along with FOSA; see file
41 // COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,
42 // Cambridge, MA 02139, USA.
44 // As a special exception, including FOSA header files in a file,
45 // instantiating FOSA generics or templates, or linking other files
46 // with FOSA objects to produce an executable application, does not
47 // by itself cause the resulting executable application to be covered
48 // by the GNU General Public License. This exception does not
49 // however invalidate any other reasons why the executable file might be
50 // covered by the GNU Public License.
51 // -----------------------------------------------------------------------
52 //fosa_app_def_sched.h
53 //==============================================
54 // ******** ****** ******** **********
55 // **///// /** ** **////// /** /**
56 // ** /** ** /** /** /**
57 // ******* /** ** /********* /**********
58 // **//// /** ** ////////** /**//////**
59 // ** /** ** /** /** /**
60 // ** /** ** ******** /** /**
61 // // /******/ //////// // //
63 // FOSA(Frescor Operating System Adaptation layer)
64 //================================================
65 // 26-Jun-07 SANGORRIN: comment scheduler mutex because signal_set can only be
66 // set from the scheduler itself (don't delete because it might be useful in
69 // 25-Jun-07 SANGORRIN: when posix_appsched_execute_actions had an error code
70 // was wrong. Now we clear actions before (and added destroy operation!), then
71 // execute scheduler op and then go back to main loop (when error it continued
72 // executing the rest of actions)
74 // 10-Jul-07 SANGORRIN: in the new_thread callback we need to accept the thread
75 // before suspend or activate it.
76 // -----------------------------------------------------------------------
85 #include <sys/marte_sched_events_codes.h>
87 #include <misc/error_checks.h>
89 // Full error checking option
90 // --------------------------
91 // Uncomment the following definition if full error checking is desired
92 // Beware that this option will introduce overhead in each context switch
94 #define FULL_ERROR_CHECKING
96 /********************************
97 * Application-defined scheduling
98 ********************************/
101 * We make the following ASSUMPTIONS:
103 * - The ADS always executes in the user memory space, so we don't
104 * need to manage the memory space translation.
106 * - Only one application scheduler exists, so we don't need a
112 * Data structures for the scheduler thread
115 // data structure that is passed to the scheduler thread
116 struct scheduler_thread_data {
117 fosa_ads_scheduler_ops_t scheduler_ops; // entry points
118 size_t scheduler_data_size; // size of scheduler data
119 void * scheduler_data; // pointer to scheduler data
120 void * init_args; // pointer to init args
121 size_t init_args_size; // size of init args
122 sigset_t sch_signal_set; // set of signals used by the
124 // pthread_mutex_t sch_mutex; // mutex used to share info with
126 pthread_key_t clock_key; // key to thread-specific data where
127 // a clock id is stored
128 pthread_key_t msg_key; // key to thread-specific data with
129 // a pointer to the messages for
130 // explicit invoke operations
133 // data structure used in the explicit call with data operation
134 struct explicit_call_info {
142 static struct scheduler_thread_data schedthreaddata;
143 static pthread_t scheduler_thread_id;
146 * Code of application-defined thread. The current version of MaRTE OS
147 * requires a thread to perform the scheduler actions.
148 * In the future it is expected that this thread will not be necessary.
150 void * scheduler_thread_code(void *arg) {
151 fosa_ads_actions_t sched_actions;
152 struct posix_appsched_event event;
153 struct scheduler_thread_data *sch_thread_data=
154 (struct scheduler_thread_data *) arg;
155 void * scheduler_data = sch_thread_data->scheduler_data;
156 posix_appsched_eventset_t event_set;
157 fosa_abs_time_t current_time;
158 struct timespec current_time_tspec;
159 struct explicit_call_info *call_info;
163 // set the clock to be used by the scheduler
164 CHK(posix_appschedattr_setclock(FOSA_CLOCK_REALTIME));
166 // set the timeouts to be used in the scheduler to be absolute
167 CHK(posix_appschedattr_setflags (POSIX_APPSCHED_ABSTIMEOUT));
169 // set the mask of events to mask all events except for those
170 // corresponding to non-null entry points
171 CHK(posix_appsched_fillset(&event_set));
173 if (sch_thread_data->scheduler_ops.new_thread!=NULL) {
174 CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_NEW));
177 if (sch_thread_data->scheduler_ops.thread_terminate!=NULL) {
178 CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_TERMINATE));
181 if (sch_thread_data->scheduler_ops.thread_ready!=NULL) {
182 CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_READY));
185 if (sch_thread_data->scheduler_ops.thread_block!=NULL) {
186 CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_BLOCK));
188 // change_sched_param_thread
189 if (sch_thread_data->scheduler_ops.change_sched_param_thread!=NULL) {
190 CHK(posix_appsched_delset(&event_set, POSIX_APPSCHED_CHANGE_SCHED_PARAM));
192 // explicit_call_with_data
193 if (sch_thread_data->scheduler_ops.explicit_call_with_data!=NULL) {
194 CHK(posix_appsched_delset(&event_set, POSIX_APPSCHED_EXPLICIT_CALL));
196 // notification_for_thread
197 if (sch_thread_data->scheduler_ops.notification_for_thread!=NULL) {
198 CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_TASK_NOTIFICATION));
201 if (sch_thread_data->scheduler_ops.timeout!=NULL) {
202 CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_TIMEOUT));
205 if (sch_thread_data->scheduler_ops.signal!=NULL) {
206 CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_SIGNAL));
208 // set the event mask
209 CHK(posix_appschedattr_seteventmask(&event_set));
211 // invoke the init entry point
212 sch_thread_data->scheduler_ops.init(scheduler_data,
213 sch_thread_data->init_args);
215 // clear the scheduling actions data structure
216 CHK(posix_appsched_actions_init(&(sched_actions.actions)));
217 sched_actions.timeout_ptr=NULL;
218 sched_actions.rejected=false;
219 sched_actions.activated=false;
220 sched_actions.suspended=false;
222 // lock the scheduler mutex
223 // CHK(pthread_mutex_lock(&(sch_thread_data->sch_mutex)));
225 // main scheduler loop
228 // NOTE: Put here code shared with app to be protected with the mutex
230 // unlock the scheduler mutex before waiting
231 // CHK(pthread_mutex_unlock(&(sch_thread_data->sch_mutex)));
233 // execute pending scheduling actions and wait for next event
234 err=posix_appsched_execute_actions
235 (&(sched_actions.actions),&(sch_thread_data->sch_signal_set),
236 sched_actions.timeout_ptr,¤t_time_tspec,&event);
238 current_time = fosa_timespec_to_abs_time(current_time_tspec);
240 // clear the scheduling actions data structure
241 CHK(posix_appsched_actions_destroy (&(sched_actions.actions)));
242 CHK(posix_appsched_actions_init(&(sched_actions.actions)));
243 sched_actions.timeout_ptr=NULL;
244 sched_actions.rejected=false;
245 sched_actions.activated=false;
246 sched_actions.suspended=false;
248 // lock the scheduler mutex to perform scheduler operations
249 // in mutual exclusion
250 // CHK(pthread_mutex_lock(&(sch_thread_data->sch_mutex)));
253 // determine which kind of event has arrived, and invoke appropriate
255 switch (event.event_code) {
256 case POSIX_APPSCHED_NEW:
257 sch_thread_data->scheduler_ops.new_thread
262 if (!sched_actions.rejected) {
263 // create a memory area for the explicit messages
264 call_info=(struct explicit_call_info *)
265 malloc(sizeof(struct explicit_call_info));
266 if (call_info==NULL) {
267 CHK(posix_appsched_actions_addreject
268 (&(sched_actions.actions),event.thread));
270 // clear actions, we need to accept the thread first
271 CHK(posix_appsched_actions_destroy (&(sched_actions.actions)));
272 CHK(posix_appsched_actions_init(&(sched_actions.actions)));
274 CHK(posix_appsched_actions_addaccept
275 (&(sched_actions.actions),event.thread));
276 // store the memory area in thread-specific data
277 CHK(pthread_setspecific_for
278 (schedthreaddata.msg_key,event.thread,call_info));
279 // and activate or suspend the thread
280 if (sched_actions.suspended) {
281 CHK(posix_appsched_actions_addsuspend
282 (&(sched_actions.actions),event.thread));
284 CHK(posix_appsched_actions_addactivate
285 (&(sched_actions.actions),event.thread));
290 case POSIX_APPSCHED_TERMINATE:
291 sch_thread_data->scheduler_ops.thread_terminate
297 case POSIX_APPSCHED_READY:
298 sch_thread_data->scheduler_ops.thread_ready
303 // activate the thread unless suspended or already activated
304 if (!sched_actions.suspended && !sched_actions.activated) {
305 CHK(posix_appsched_actions_addactivate
306 (&(sched_actions.actions),event.thread));
309 case POSIX_APPSCHED_BLOCK:
310 sch_thread_data->scheduler_ops.thread_block
316 case POSIX_APPSCHED_CHANGE_SCHED_PARAM:
317 sch_thread_data->scheduler_ops.change_sched_param_thread
323 //case POSIX_APPSCHED_EXPLICIT_CALL_WITH_DATA:
324 //sch_thread_data->scheduler_ops.explicit_call_with_data
327 // event.event_info.info,event.info_size,
328 // &reply, &reply_size,
331 case POSIX_APPSCHED_EXPLICIT_CALL:
332 CHK(pthread_getspecific_from
333 (schedthreaddata.msg_key,event.thread,(void **)(&call_info)));
334 sch_thread_data->scheduler_ops.explicit_call_with_data
338 call_info->info_size,
339 call_info->reply_ptr,
340 &(call_info->reply_size),
343 // activate the thread unless suspended or already activated
344 if (!sched_actions.suspended && !sched_actions.activated) {
345 CHK(posix_appsched_actions_addactivate
346 (&(sched_actions.actions),event.thread));
349 case POSIX_APPSCHED_TASK_NOTIFICATION:
350 clk=(clockid_t) pthread_getspecific(sch_thread_data->clock_key);
351 sch_thread_data->scheduler_ops.notification_for_thread
357 // t.b.d. check if state of thread is suspended by default
359 case POSIX_APPSCHED_TIMEOUT:
360 sch_thread_data->scheduler_ops.timeout
365 case POSIX_APPSCHED_SIGNAL:
366 sch_thread_data->scheduler_ops.signal
368 event.event_info.siginfo.si_signo,
369 *((fosa_signal_info_t *)(&(event.event_info.siginfo.si_value))),
370 // the above casting construct is used to overcome the compiler
371 // restriction that does not allow casts between unions
376 ASSERT_INFO(true,"Unexpected scheduling event received in scheduler");
377 } // end switch on event code
378 } else if (err==EINVAL) {
379 sch_thread_data->scheduler_ops.appsched_error
380 (scheduler_data, event.thread,
381 FOSA_ADS_THREAD_NOT_ATTACHED, &sched_actions);
382 } else if (err==ESRCH) {
383 sch_thread_data->scheduler_ops.appsched_error
384 (scheduler_data, event.thread,
385 FOSA_ADS_INVALID_ACTION, &sched_actions);
387 } // end of main scheduler loop
392 * fosa_ads_scheduler_create()
394 * Create the application defined scheduler
396 * The application defined scheduler is created with the primitive
397 * operations specified in the object pointed to by scheduler_ops.
399 * The clock used to read the time immediately before the invocation
400 * of each primitive operation, to be reported to the scheduler via
401 * the current_time parameter of each primitive operation is the
402 * FOSA_CLOCK_REALTIME clock.
404 * The scheduler_data_size parameter is used to request that a memory
405 * area of this size must be created and reserved for the scheduler to
406 * store its state. A pointer to this area is passed to the scheduler
407 * operations in the sched_data parameter.
409 * Parameter init_arg points to an area that contains configuration
410 * information for the scheduler. The function creates a memory area
411 * of init_arg_size bytes and copies into it the area pointed by
412 * arg. A pointer to this new created area will be passed to the
413 * primitive operation init() in its arg parameter.
415 * Returns 0 if successful; otherwise it returns an error code:
416 * EINVAL: The value of scheduler_ops was invalid
417 * EAGAIN: The system lacks enough resources to create the scheduler
419 * Alternatively, in case of error the implementation is allowed to
420 * notify it to the system console and then terminate the FRSH
421 * implementation and dependant applications
423 * The fosa_ads_scheduler_create function must be called before any
424 * other function in this header file
426 int fosa_ads_scheduler_create
427 (const fosa_ads_scheduler_ops_t * scheduler_ops,
428 size_t scheduler_data_size,
430 size_t init_args_size)
433 // pthread_mutexattr_t mattr;
435 struct sched_param param;
437 #ifdef FULL_ERROR_CHECKING
438 // check for NULL scheduler operations
439 if (scheduler_ops==NULL) {
442 #endif // end if FULL_ERROR_CHECKING
444 // copy arguments in scheduler data
445 schedthreaddata.scheduler_ops=*scheduler_ops;
446 schedthreaddata.scheduler_data_size=scheduler_data_size;
447 schedthreaddata.init_args_size=init_args_size;
449 // create scheduler memory area
450 schedthreaddata.scheduler_data=malloc(scheduler_data_size);
451 if (schedthreaddata.scheduler_data==NULL) {
455 // create init args memory area and copy the init args
456 schedthreaddata.init_args=malloc(init_args_size);
457 if (schedthreaddata.init_args==NULL) {
460 memcpy(schedthreaddata.init_args,init_args,init_args_size);
462 // initialize the set of signals used by the scheduler to none
463 CHKE(sigemptyset(&(schedthreaddata.sch_signal_set)));
465 // calculate the priority
466 param.sched_priority=sched_get_priority_max(SCHED_FIFO)-
467 FOSA_ADS_SCHEDULER_PRIO_DIFF;
469 // initialize the mutex used to share data with the scheduler
470 // CHK(pthread_mutexattr_init(&mattr));
471 // we use the priority protect protocol
472 // CHK(pthread_mutexattr_setprotocol(&mattr,PTHREAD_PRIO_PROTECT));
473 // set priority ceiling
474 // CHK(pthread_mutexattr_setprioceiling(&mattr,param.sched_priority));
476 // CHK(pthread_mutex_init(&(schedthreaddata.sch_mutex),&mattr));
477 // CHK(pthread_mutexattr_destroy(&mattr));
479 // create the thread-specific data key for the clock id
480 CHK(pthread_key_create(&schedthreaddata.clock_key,NULL));
482 // create the thread-specific data key for the message pointers
483 CHK(pthread_key_create(&schedthreaddata.msg_key,NULL));
485 // set the attributes for the scheduler thread
486 err=pthread_attr_init(&attr);
490 CHK(pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED));
491 CHK(pthread_attr_setinheritsched(&attr,PTHREAD_EXPLICIT_SCHED));
492 CHK(pthread_attr_setschedpolicy(&attr,SCHED_FIFO));
493 CHK(pthread_attr_setschedparam(&attr,¶m));
494 CHK(pthread_attr_setappschedulerstate(&attr,PTHREAD_APPSCHEDULER));
495 CHK(pthread_attr_setpreemptionlevel(&attr,FOSA_ADS_SCHEDULER_LEVEL));
497 // create the scheduler thread
498 return pthread_create(&scheduler_thread_id,&attr,
499 scheduler_thread_code, (void *) &schedthreaddata);
503 * fosa_thread_attr_set_appscheduled()
505 * Set the appscheduled attribute of a thread attributes object
507 * This function is used to set the appscheduled attribute in the
508 * object pointed to by attr. This attribute controls the kind of
509 * scheduling used for threads created with it. If true, the thread is
510 * scheduled by the application scheduler. If not, it is scheduled by
511 * the system under a fixed priority scheduler
513 * Returns 0 if successful; otherwise it returns an error code:
514 * EINVAL: The value of attr is invalid
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_attr_set_appscheduled
521 (fosa_thread_attr_t *attr,
526 // set the application-defined scheduler thread
527 error_code=pthread_attr_setappscheduler(attr,scheduler_thread_id);
528 if (error_code!=0) return error_code;
531 return pthread_attr_setschedpolicy(attr,SCHED_APP);
533 return pthread_attr_setschedpolicy(attr,SCHED_FIFO);
538 * fosa_thread_attr_get_appscheduled()
540 * Get the appscheduled attribute of a thread attributes object
542 * This function is used to get the appscheduled attribute in the
543 * object pointed to by attr. This attribute controls the kind of
544 * scheduling used for threads created with it. If true, the thread is
545 * scheduled by the application scheduler. If not, it is scheduled by
546 * the system under a fixed priority scheduler.
548 * Returns 0 if successful; otherwise it returns an error code:
549 * EINVAL: The value of attr is invalid
551 * Alternatively, in case of error the implementation is allowed to
552 * notify it to the system console and then terminate the FRSH
553 * implementation and dependant applications
555 int fosa_thread_attr_get_appscheduled
556 (const fosa_thread_attr_t *attr,
559 int policy, ret_value;
561 ret_value=pthread_attr_getschedpolicy(attr,&policy);
563 if (policy==SCHED_APP) {
573 * fosa_thread_attr_set_appsched_params()
575 * Set the appsched_param attribute of a thread attributes object
577 * This function is used to set the appsched_param attribute in the
578 * object pointed to by attr. For those threads with appscheduled set
579 * to true, this attribute represents the application-specific
580 * scheduling parameters. If successful, the function shall set the
581 * size of the appsched_param attribute to the value specified by
582 * paramsize, and shall copy the scheduling parameters occupying
583 * paramsize bytes and pointed to by param into that attribute
585 * Returns 0 if successful; otherwise it returns an error code:
586 * EINVAL: The value of attr is invalid, or paramsize is less than
587 * zero or larger than FOSA_ADS_SCHEDPARAM_MAX
589 * Alternatively, in case of error the implementation is allowed to
590 * notify it to the system console and then terminate the FRSH
591 * implementation and dependant applications
593 int fosa_thread_attr_set_appsched_params
594 (fosa_thread_attr_t *attr,
598 return pthread_attr_setappschedparam(attr,param,paramsize);
602 * fosa_thread_attr_get_appsched_params()
604 * Get the appsched_param attribute of a thread attributes object
606 * This function is used to get the appsched_param attribute from the
607 * object pointed to by attr. For those threads with appscheduled set
608 * to true, this attribute represents the application-specific
609 * scheduling parameters. If successful, the function shall set the
610 * value pointed to by paramsize to the size of the appsched_param
611 * attribute, and shall copy the scheduling parameters occupying
612 * paramsize bytes into the variable pointed to by param. This
613 * variable should be capable of storing a number of bytes equal to
616 * Returns 0 if successful; otherwise it returns an error code:
617 * EINVAL: The value of attr is invalid
619 * Alternatively, in case of error the implementation is allowed to
620 * notify it to the system console and then terminate the FRSH
621 * implementation and dependant applications
623 int fosa_thread_attr_get_appsched_params
624 (const fosa_thread_attr_t *attr,
628 return pthread_attr_getappschedparam(attr,param,paramsize);
632 * fosa_ads_set_appscheduled()
634 * Dynamically set the appscheduled attribute of a thread
636 * This function is used to dynamically set the appscheduled attribute
637 * of the thread identified by thread. This attribute controls the
638 * kind of scheduling used for threads created with it. If true, the
639 * thread is scheduled by the application scheduler. If not, it is
640 * scheduled by the system under a fixed priority scheduler.
642 * Returns 0 if successful; otherwise it returns an error code:
643 * EINVAL: The value of thread is invalid
645 * EREJECT: the attachment of the thread to the frsh schehduler
646 * was rejected by the frsh scheduler possibly because of
647 * incorrect attributes, or because the requested minimum
648 * capacity cannot be guaranteed
650 * Alternatively, in case of error the implementation is allowed to
651 * notify it to the system console and then terminate the FRSH
652 * implementation and dependant applications
654 int fosa_ads_set_appscheduled
655 (fosa_thread_id_t thread,
659 int current_policy, new_policy;
660 struct sched_param param;
662 // switch to the appropriate scheduling policy
663 CHK(pthread_getschedparam(thread,¤t_policy,¶m));
664 if (((current_policy==SCHED_APP) && (!appscheduled)) ||
665 ((current_policy!=SCHED_APP) && appscheduled)) {
667 new_policy=SCHED_APP;
668 // set the application-defined scheduler thread
669 error_code=pthread_setappscheduler(thread,scheduler_thread_id);
670 if (error_code!=0) return error_code;
672 new_policy=SCHED_FIFO;
674 error_code=pthread_setschedparam(thread,new_policy,¶m);
680 * fosa_ads_getappscheduled()
682 * Dynamically get the appscheduled attribute of a thread
684 * This function is used to dynamically get the appscheduled attribute
685 * of the thread identified by thread. This attribute controls the
686 * kind of scheduling used for threads created with it. If true, the
687 * thread is scheduled by the application scheduler. If not, it is
688 * scheduled by the system under a fixed priority scheduler
690 * Returns 0 if successful; otherwise it returns an error code:
691 * EINVAL: The value of thread is invalid
693 * Alternatively, in case of error the implementation is allowed to
694 * notify it to the system console and then terminate the FRSH
695 * implementation and dependant applications
697 int fosa_ads_get_appscheduled
698 (fosa_thread_id_t thread,
701 int error_code, policy;
702 struct sched_param param;
704 error_code=pthread_getschedparam(thread,&policy,¶m);
708 *appscheduled = (policy==SCHED_APP);
715 * fosa_ads_setappschedparam()
717 * Dynamically set the appsched_param attribute of a thread
719 * This function is used to dynamically set the appsched_param
720 * attribute of the thread identified by thread. For those threads
721 * with appscheduled set to true, this attribute represents the
722 * application-specific scheduling parameters. If successful, the
723 * function shall set the size of the appsched_param attribute to the
724 * value specified by paramsize, and shall copy the scheduling
725 * parameters occupying paramsize bytes and pointed to by param into
728 * Returns 0 if successful; otherwise it returns an error code:
729 * EINVAL: The value of thread is invalid, or paramsize is less than
730 * zero or larger than FOSA_ADS_SCHEDPARAM_MAX
732 * Alternatively, in case of error the implementation is allowed to
733 * notify it to the system console and then terminate the FRSH
734 * implementation and dependant applications
736 int fosa_ads_set_appsched_params
737 (fosa_thread_id_t thread,
741 return pthread_setappschedparam(thread,param,paramsize);
745 * fosa_ads_get_appsched_params()
747 * Dynamically get the appsched_param attribute of a thread
749 * This function is used to dynamically get the appsched_param
750 * attribute of the thread identified by thread. For those threads
751 * with appscheduled set to true, this attribute represents the
752 * application-specific scheduling parameters. If successful, the
753 * function shall set the variable pointed to by paramsize to the size
754 * of the appsched_param attribute, and shall copy the scheduling
755 * parameters occupying paramsize bytes into the variable pointed to
756 * by param. This variable should be capable of storing a number of
757 * bytes equal to paramsize.
759 * Returns 0 if successful; otherwise it returns an error code:
760 * EINVAL: The value of thread is invalid, or paramsize is less than
761 * zero or larger than FOSA_ADS_SCHEDPARAM_MAX
763 * Alternatively, in case of error the implementation is allowed to
764 * notify it to the system console and then terminate the FRSH
765 * implementation and dependant applications.
767 int fosa_ads_get_appsched_params
768 (fosa_thread_id_t thread,
772 return pthread_getappschedparam(thread,param,paramsize);
776 /*********************************
779 * A scheduling actions object is used to specify a series of actions
780 * to be performed by the system at the end of a scheduler primitive
781 * operation. The order of the actions added to the object shall be
784 *********************************/
787 * fosa_adsactions_add_reject()
789 * Add a reject-thread action
791 * This function adds a thread-reject action to the object referenced
792 * by sched_actions, that will serve to notify that the thread
793 * identified by thread has not been accepted by the scheduler to be
794 * scheduled by it, possibly because the thread contained invalid
795 * application scheduling attributes, or because there are not enough
796 * resources for the new thread. At the end of the new_thread()
797 * scheduler primitive operation, the parent of the rejected thread
798 * waiting on a fosa_thread_create() or the rejected thread itself
799 * waiting on a fosa_ads_set_appscheduled() function shall complete the
800 * function with an error code of EREJECT. If no reject-thread action
801 * is added during the new_thread() scheduler primitive operation, the
802 * thread is accepted to be scheduled by the scheduler and the
803 * associated fosa_thread_create() or the fosa_ads_set_appscheduled()
804 * function shall be completed without error. For the function to
805 * succeed, it has to be called from the new_thread() primitive
806 * operation and for the thread that is requesting attachment to the
809 * Returns 0 if successful; otherwise it returns an error code:
810 * ENOMEM: There is insufficient memory to add this action
811 * FOSA_EPOLICY: The thread specified by thread is not the one requesting
812 * attachment to the scheduler, or the function is not being
813 * called from the new_thread primitive operation
814 * EINVAL: The value specified by sched_actions is invalid
816 * Alternatively, in case of error the implementation is allowed to
817 * notify it to the system console and then terminate the FRSH
818 * implementation and dependant applications
820 int fosa_adsactions_add_reject(
821 fosa_ads_actions_t *sched_actions,
822 fosa_thread_id_t thread)
824 #ifdef FULL_ERROR_CHECKING
826 if (!pthread_equal(pthread_self(),scheduler_thread_id)) {
829 #endif // end if FULL_ERROR_CHECKING
830 sched_actions->rejected=true;
831 return posix_appsched_actions_addreject(&(sched_actions->actions),thread);
835 * fosa_adsactions_add_activate()
837 * Add a thread-activate action
839 * This function adds a thread-activate action to the object
840 * referenced by sched_actions. In case the thread had been previously
841 * suspended via posix_appsched_actions_addsuspend(), it will be
842 * activated at the end of the primitive operation.
844 * In those implementations that do not support urgency scheduling,
845 * the urgencu value is ignored. These implementations cannot support
846 * the frsh hierarchical scheduling module.
848 * In those implementations supporting urgency-scheduling, the action
849 * will cause the change of the urgency of the thread to the value
850 * specified in the urgency argument. Besides, if the thread was
851 * already active at the time the thread-activate action is executed,
852 * the change or urgency will imply a reordering of the thread in its
853 * priority queue, so that for threads of the same priority, those
854 * with more urgency will be scheduled before those of less urgency.
856 * Returns 0 if successful; otherwise it returns an error code:
857 * ENOMEM: There is insufficient memory to add this action
858 * FOSA_EPOLICY: The thread specified by thread has its appscheduled
859 * attribute set to false,
860 * EINVAL: The value specified by sched_actions is invalid
862 * Alternatively, in case of error the implementation is allowed to
863 * notify it to the system console and then terminate the FRSH
864 * implementation and dependant applications
866 int fosa_adsactions_add_activate(
867 fosa_ads_actions_t *sched_actions,
868 fosa_thread_id_t thread,
869 fosa_ads_urgency_t urgency)
871 #ifdef FULL_ERROR_CHECKING
873 struct sched_param param;
876 CHK(pthread_getschedparam(thread,&policy,¶m));
877 if (policy!=SCHED_APP) {
880 #endif // end if FULL_ERROR_CHECKING
882 sched_actions->activated=true;
883 return posix_appsched_actions_addactivate(&(sched_actions->actions),thread);
887 * fosa_adsactions_add_suspend()
889 * Add a thread-suspend action
891 * This function adds a thread-suspend action to the object referenced
892 * by sched_actions, that will cause the thread identified by thread
893 * to be suspended waiting for a thread-activate action at the end of
894 * the scheduler operation. If the thread was already waiting for a
895 * thread-activate action the thread-suspend action has no effect. It
896 * is an error trying to suspend a thread that is blocked by the
899 * Returns 0 if successful; otherwise it returns an error code:
900 * ENOMEM: There is insufficient memory to add this action
901 * FOSA_EPOLICY: The thread specified by thread has its appscheduled
902 * attribute set to false,
903 * EINVAL: The value specified by sched_actions is invalid
905 * Alternatively, in case of error the implementation is allowed to
906 * notify it to the system console and then terminate the FRSH
907 * implementation and dependant applications
909 int fosa_adsactions_add_suspend(
910 fosa_ads_actions_t *sched_actions,
911 fosa_thread_id_t thread)
913 #ifdef FULL_ERROR_CHECKING
915 struct sched_param param;
918 CHK(pthread_getschedparam(thread,&policy,¶m));
919 if (policy!=SCHED_APP) {
922 #endif // end if FULL_ERROR_CHECKING
923 sched_actions->suspended=true;
924 return posix_appsched_actions_addsuspend(&(sched_actions->actions),thread);
928 * fosa_adsactions_add_timeout()
930 * Add a timeout action
932 * This function adds a timeout action to the object referenced by
933 * sched_actions, that will cause the timeout() scheduler operation to
934 * be invoked if no other scheduler operation is invoked before
935 * timeout expires. The timeout shall expire when the clock specified by
936 * clock_id reaches the absolute time specified by the at_time
939 * Returns 0 if successful; otherwise it returns an error code:
940 * ENOMEM: There is insufficient memory to add this action
941 * EINVAL: The value specified by sched_actions is invalid
943 * Alternatively, in case of error the implementation is allowed to
944 * notify it to the system console and then terminate the FRSH
945 * implementation and dependant applications
947 int fosa_adsactions_add_timeout(
948 fosa_ads_actions_t *sched_actions,
949 fosa_clock_id_t clock_id,
950 const fosa_abs_time_t *at_time)
952 sched_actions->timeout= fosa_abs_time_to_timespec(*at_time);
953 sched_actions->timeout_ptr=&(sched_actions->timeout);
958 * fosa_adsactions_add_thread_notification()
960 * Add a timed-thread-notification action
962 * This function adds a thread-notification action associated with the
963 * thread specified in the thread argument that will cause the
964 * notification_for_thread() scheduler operation to be invoked at the
965 * time specified by at_time. This operation shall be invoked when the
966 * clock specified by clock_id reaches the absolute time specified by
967 * the at_time argument. In particular, a cpu-time clock may be used
968 * for parameter clock_id.Only one thread-notification can be active
969 * for each thread and clock. Calling the function shall remove the
970 * former thread-notification, if any, that had been programmed for
971 * the same thread and clock. A value of NULL for parameter at_time is
972 * used to cancel a previous thread-notification, if any, for the
973 * thread specified by thread and the clock specified by clock_id.
975 * Returns 0 if successful; otherwise it returns an error code:
976 * ENOMEM: There is insufficient memory to add this action
977 * FOSA_EPOLICY: The thread specified by thread has its appscheduled
978 * attribute set to false,
979 * EINVAL: The value specified by sched_actions is invalid
981 * Alternatively, in case of error the implementation is allowed to
982 * notify it to the system console and then terminate the FRSH
983 * implementation and dependant applications
985 int fosa_adsactions_add_thread_notification(
986 fosa_ads_actions_t *sched_actions,
987 fosa_thread_id_t thread,
988 fosa_clock_id_t clock_id,
989 const fosa_abs_time_t *at_time)
991 #ifdef FULL_ERROR_CHECKING
993 struct sched_param param;
996 CHK(pthread_getschedparam(thread,&policy,¶m));
997 if (policy!=SCHED_APP) {
1000 #endif // end if FULL_ERROR_CHECKING
1002 // the implementation uses a timer that generates a signal
1003 // with the thread id encoded in the signal info
1004 // the clock id is stored in thread-specific data
1006 // store the clock id in thread-specific data
1007 CHK(pthread_setspecific(schedthreaddata.clock_key,(void *) clock_id));
1009 // t.b.d. this function is currently not used,
1010 // therefore we don't implement it yet
1016 * fosa_ads_set_handled_signal_set()
1018 * Specifiy the set of signals that will be handled by the application
1021 * This function is used to dynamically set the set of signals that
1022 * are handled by the application scheduler. When a signal included
1023 * in this set is generated, the signal() primitive operation of the
1024 * application scheduler shall be executed. When a signal in tis set
1025 * is generated, it shall always imply the execution of the signal()
1026 * primitive operation, regardless of whether that signal could be
1027 * accepted by some other thread. Once the signal() primitive
1028 * operation is executed the signal is consumed, so no signal handlers
1029 * shall be executed and no threads using a sigwait operation shall
1030 * return for that particular signal instance. For this function to
1031 * succeed, it has to be called from a primitive operation of a
1034 * Returns 0 if successful; otherwise it returns an error code:
1035 * FOSA_EPOLICY: The function has not been called from a scheduler
1036 * primitive operation
1037 * EINVAL: The value specified by set is invalid
1039 * Alternatively, in case of error the implementation is allowed to
1040 * notify it to the system console and then terminate the FRSH
1041 * implementation and dependant applications
1043 int fosa_ads_set_handled_signal_set(fosa_signal_t set[], int size)
1047 #ifdef FULL_ERROR_CHECKING
1049 if (!pthread_equal(pthread_self(),scheduler_thread_id)) {
1050 return FOSA_EPOLICY;
1052 #endif // end if FULL_ERROR_CHECKING
1053 // empty the signal set
1054 CHKE(sigemptyset(&(schedthreaddata.sch_signal_set)));
1055 // loop for all signals in set, to add them to the set of signals used
1057 for(i=0;i<size;i++) {
1058 CHKE(sigaddset(&(schedthreaddata.sch_signal_set),set[i]));
1065 * fosa_signal_queue_scheduler()
1067 * Queue a signal destinated to the scheduler
1069 * This is a special case of fosa_signal_queue() in which the
1070 * destinator is the scheduler itself. It is needed by the service
1071 * thread to notify the results to the scheduler.
1073 * The problem with this case is that, depending on the implementation,
1074 * this call would be translated to a true signal or to a scheduler
1075 * notification message.
1077 * Besides for the scheduler we don't have always a destinator
1078 * thread_id needed in fosa_signal_queue for OSE.
1080 * So the fosa implementation will solve this issue internally.
1082 * Returns 0 if successful; otherwise it returns an error code:
1083 * FOSA_EINVAL: the signal specified by signal is not
1084 * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
1086 * FOSA_EAGAIN: no resources are available to queue the signal; the
1087 * maximum number of queued signals has been reached, or a
1088 * systemwide resource limit has been exceeded
1090 * Alternatively, in case of error the implementation is allowed to
1091 * notify it to the system console and then terminate the FRSH
1092 * implementation and dependant applications
1094 int fosa_signal_queue_scheduler(fosa_signal_t signal, fosa_signal_info_t info)
1096 // In MaRTE OS this function is completely equivalent to
1097 // fosa_signal_queue, because there is no notion of receiver.
1098 fosa_thread_id_t receiver = 0; // Dummy value, not used by MaRTE OS
1099 return fosa_signal_queue(signal, info, receiver);
1103 * fosa_ads_invoke_withdata()
1105 * Explicitly invoke the scheduler, with data
1107 * This function can be used by any thread in the process to invoke
1108 * the ads scheduler or to share data with it.
1110 * If successful, the function shall cause the execution of the
1111 * primitive operation explicit_call_with_data() of the ads scheduler
1112 * with its thread parameter equal to the thread ID of the calling
1113 * thread, and its msg_size parameter equal to msg_size. In addition,
1114 * if msg_size is larger than zero, the function shall make available
1115 * to the scheduler a memory area whose contents are identical to the
1116 * memory area pointed to by msg in the msg parameter of the
1117 * explicit_call_with_data() primitive operation (note that copying
1118 * the information is not needed).
1120 * The function shall not return until the system has finished
1121 * execution of the explicit_call_with_data() primitive operation. If
1122 * the reply argument is non NULL, the memory area pointed to by the
1123 * reply parameter of explicit_call_with_data() primitive operation is
1124 * copied into the memory area pointed to by reply, and its size is
1125 * copied into the variable pointed to by reply_size. The size of the
1126 * reply information is limited to the value FOSA_ADS_SCHEDINFO_MAX.
1128 * The function shall fail if the size specified by msg_size is larger
1129 * than FOSA_ADS_SCHEDINFO_MAX. The function shall fail if primitive
1130 * operation explicit_call_with_data() is set to NULL for the ads
1133 * Returns 0 if successful; otherwise it returns an error code:
1134 * FOSA_EPOLICY: The function been called from inside a scheduler
1135 * primitive operation
1136 * EINVAL: The value of msg_size is less than zero or larger than
1137 * FOSA_ADS_SCHEDINFO_MAX
1138 * FOSA_EMASKED: The operation cannot be executed because the primitive
1139 * operation explicit_call_with_data() is set to NULL
1141 * Alternatively, in case of error the implementation is allowed to
1142 * notify it to the system console and then terminate the FRSH
1143 * implementation and dependant applications
1145 int fosa_ads_invoke_withdata
1146 (const void *msg, size_t msg_size, void *reply, size_t *reply_size)
1148 // The corresponding function in MaRTE OS is not yet implemented
1149 // We implement this function by creating a memory area for each thread
1150 // and using the invoke with no data function
1151 struct explicit_call_info * call_info;
1154 #ifdef FULL_ERROR_CHECKING
1156 if (pthread_equal(pthread_self(),scheduler_thread_id)) {
1157 return FOSA_EPOLICY;
1159 if (msg_size>FOSA_ADS_SCHEDINFO_MAX) {
1162 if (schedthreaddata.scheduler_ops.explicit_call_with_data==NULL) {
1163 return FOSA_EMASKED;
1165 #endif // end if FULL_ERROR_CHECKING
1167 call_info = (struct explicit_call_info *)
1168 pthread_getspecific(schedthreaddata.msg_key);
1169 ASSERT_INFO(call_info!=NULL,
1170 "Error in access to specific data for explicit call");
1171 if (call_info==NULL) return EINVAL;
1172 call_info->info_size=msg_size;
1173 // the following type cast is to avoid warnings, but should be OK
1174 call_info->info_ptr=(void *)msg;
1175 call_info->reply_ptr=reply;
1176 error_code=posix_appsched_invoke_scheduler(0);
1177 if (reply != NULL) {
1178 *reply_size=call_info->reply_size;