]> rtime.felk.cvut.cz Git - frescor/fosa.git/blob - src_marte/fosa_app_def_sched.c
Moving fosa_signal_queue_scheduler() from threads_and_signals.h to
[frescor/fosa.git] / src_marte / fosa_app_def_sched.c
1 // -----------------------------------------------------------------------
2 //  Copyright (C) 2006 - 2007 FRESCOR consortium partners:
3 //
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
10 //    ENEA                                   SWEDEN
11 //    Thales Communication S.A.              FRANCE
12 //    Visual Tools S.A.                      SPAIN
13 //    Rapita Systems Ltd                     UK
14 //    Evidence                               ITALY
15 //
16 //    See http://www.frescor.org for a link to partners' websites
17 //
18 //           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
21 //        made of this code.
22 //
23 //  This file is part of the FRSH implementation
24 //
25 //  FRSH is free software; you can  redistribute it and/or  modify
26 //  it under the terms of  the GNU General Public License as published by
27 //  the Free Software Foundation;  either  version 2, or (at  your option)
28 //  any later version.
29 //
30 //  FRSH  is distributed  in  the hope  that  it  will  be useful,  but
31 //  WITHOUT  ANY  WARRANTY;     without  even the   implied   warranty  of
32 //  MERCHANTABILITY  or  FITNESS FOR  A  PARTICULAR PURPOSE. See  the  GNU
33 //  General Public License for more details.
34 //
35 //  You should have  received a  copy of  the  GNU  General Public License
36 //  distributed  with  FRSH;  see file COPYING.   If not,  write to the
37 //  Free Software  Foundation,  59 Temple Place  -  Suite 330,  Boston, MA
38 //  02111-1307, USA.
39 //
40 // -----------------------------------------------------------------------
41 //fosa_app_def_sched.h
42 //==============================================
43 //  ********  ******    ********  **********
44 //  **///// /**    **  **//////  /**     /**
45 //  **      /**    ** /**        /**     /**
46 //  ******* /**    ** /********* /**********
47 //  **////  /**    ** ////////** /**//////**
48 //  **      /**    **        /** /**     /**
49 //  **      /**    **  ********  /**     /**
50 //  //       /******/  ////////   //      //
51 //
52 // FOSA(Frescor Operating System Adaptation layer)
53 //================================================
54
55 #include "fosa_app_def_sched.h"
56 #include "fosa_configuration_parameters.h"
57 #include "fosa_threads_and_signals.h"
58 #include "frsh_error.h"
59 #include "frsh_fosa.h"
60
61 #include <pthread.h>
62 #include <stdio.h>
63 #include <malloc.h>
64 #include <sched.h>
65 #include <errno.h>
66 #include <sys/marte_sched_events_codes.h>
67
68 #include <misc/error_checks.h>
69
70 // Full error checking option
71 // --------------------------
72 // Uncomment the following definition if full error checking is desired
73 // Beware that this option will introduce overhead in each context switch
74
75 #define FULL_ERROR_CHECKING
76
77 /********************************
78  * Application-defined scheduling
79  ********************************/
80
81 /**
82  * We make the following ASSUMPTIONS:
83  *
84  * - The ADS always executes in the user memory space, so we don't
85  *   need to manage the memory space translation.
86  *
87  * - Only one application scheduler exists, so we don't need a
88  *   scheduler_id.
89  **/
90
91
92 /**
93  *  Data structures for the scheduler thread
94  **/
95
96 // data structure that is passed to the scheduler thread
97 struct scheduler_thread_data {
98   fosa_ads_scheduler_ops_t scheduler_ops; // entry points
99   size_t scheduler_data_size;             // size of scheduler data
100   void * scheduler_data;                  // pointer to scheduler data
101   void * init_args;                       // pointer to init args
102   size_t init_args_size;                  // size of init args
103   sigset_t sch_signal_set;                // set of signals used by the
104                                           // scheduler
105   pthread_mutex_t sch_mutex;              // mutex used to share info with
106                                           // the scheduler
107   pthread_key_t clock_key;                // key to thread-specific data where
108                                           // a clock id is stored
109   pthread_key_t msg_key;                  // key to thread-specific data with
110                                           // a pointer to the messages for
111                                           // explicit invoke operations
112 };
113
114 // data structure used in the explicit call with data operation
115 struct explicit_call_info {
116   size_t info_size;
117   void * info_ptr;
118   size_t reply_size;
119   void * reply_ptr;
120 };
121
122 // static variables
123 static struct scheduler_thread_data schedthreaddata;
124 static pthread_t scheduler_thread_id;
125
126 /**
127  *  Code of application-defined thread. The current version of MaRTE OS
128  *  requires a thread to perform the scheduler actions.
129  *  In the future it is expected that this thread will not be necessary.
130  **/
131 void * scheduler_thread_code(void *arg) {
132   fosa_ads_actions_t sched_actions;
133   struct posix_appsched_event event;
134   struct scheduler_thread_data *sch_thread_data=
135     (struct scheduler_thread_data *) arg;
136   void * scheduler_data = sch_thread_data->scheduler_data;
137   posix_appsched_eventset_t event_set;
138   struct timespec current_time;
139   sigset_t copy_of_signalset;
140   struct explicit_call_info *call_info;
141   clockid_t clk;
142   int err;
143
144   // set the clock to be used by the scheduler
145   CHK(posix_appschedattr_setclock(FOSA_CLOCK_REALTIME));
146
147   // set the timeouts to be used in the scheduler to be absolute
148   posix_appschedattr_setflags (POSIX_APPSCHED_ABSTIMEOUT);
149
150   // set the mask of events to mask all events except for those
151   // corresponding to non-null entry points
152   CHK(posix_appsched_fillset(&event_set));
153   // new_thread
154   if (sch_thread_data->scheduler_ops.new_thread!=NULL) {
155     CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_NEW));
156   }
157   // thread_terminate
158   if (sch_thread_data->scheduler_ops.thread_terminate!=NULL) {
159     CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_TERMINATE));
160   }
161   // thread_ready
162   if (sch_thread_data->scheduler_ops.thread_ready!=NULL) {
163     CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_READY));
164   }
165   // thread_block
166   if (sch_thread_data->scheduler_ops.thread_block!=NULL) {
167     CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_BLOCK));
168   }
169   // change_sched_param_thread
170   if (sch_thread_data->scheduler_ops.change_sched_param_thread!=NULL) {
171     CHK(posix_appsched_delset(&event_set,
172                               POSIX_APPSCHED_CHANGE_SCHED_PARAM));
173   }
174   // explicit_call_with_data
175   if (sch_thread_data->scheduler_ops.explicit_call_with_data!=NULL) {
176     CHK(posix_appsched_delset(&event_set,
177                               POSIX_APPSCHED_EXPLICIT_CALL));
178   }
179   // notification_for_thread
180   if (sch_thread_data->scheduler_ops.notification_for_thread!=NULL) {
181     CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_TASK_NOTIFICATION));
182   }
183   // timeout
184   if (sch_thread_data->scheduler_ops.timeout!=NULL) {
185     CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_TIMEOUT));
186   }
187   // signal
188   if (sch_thread_data->scheduler_ops.signal!=NULL) {
189     CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_SIGNAL));
190   }
191   // set the event mask
192   CHK(posix_appschedattr_seteventmask(&event_set));
193
194   // invoke the init entry point
195   sch_thread_data->scheduler_ops.init(scheduler_data,
196                                       sch_thread_data->init_args);
197
198   // clear the scheduling actions data structure
199   CHK(posix_appsched_actions_init(&(sched_actions.actions)));
200   sched_actions.timeout_ptr=NULL;
201   sched_actions.rejected=false;
202   sched_actions.activated=false;
203   sched_actions.suspended=false;
204
205   // lock the scheduler mutex
206   CHK(pthread_mutex_lock(&(sch_thread_data->sch_mutex)));
207
208   // main scheduler loop
209   while (true) {
210
211     // copy the set of signals to be handled with mutex locked
212     copy_of_signalset=sch_thread_data->sch_signal_set;
213
214     // unlock the scheduler mutex before waiting
215     CHK(pthread_mutex_unlock(&(sch_thread_data->sch_mutex)));
216
217     // execute pending scheduling actions and wait for next event
218     err=posix_appsched_execute_actions
219       (&(sched_actions.actions),&copy_of_signalset,
220        sched_actions.timeout_ptr,&current_time,&event);
221     if (err==EINVAL) {
222         sch_thread_data->scheduler_ops.appsched_error
223           (scheduler_data,
224            event.thread,
225            FOSA_ADS_THREAD_NOT_ATTACHED,
226            &sched_actions);
227     } else if (err==ESRCH) {
228         sch_thread_data->scheduler_ops.appsched_error
229           (scheduler_data,
230            event.thread,
231            FOSA_ADS_INVALID_ACTION,
232            &sched_actions);
233     }
234
235     // clear the scheduling actions data structure
236     CHK(posix_appsched_actions_init(&(sched_actions.actions)));
237     sched_actions.timeout_ptr=NULL;
238     sched_actions.rejected=false;
239     sched_actions.activated=false;
240     sched_actions.suspended=false;
241
242     // lock the scheduler mutex to perform scheduler operations
243     // in mutual exclusion
244     CHK(pthread_mutex_lock(&(sch_thread_data->sch_mutex)));
245
246     // determine which kind of event has arrived, and invoke appropriate
247     // entry point
248     switch (event.event_code) {
249       case POSIX_APPSCHED_NEW:
250         sch_thread_data->scheduler_ops.new_thread
251           (scheduler_data,
252            event.thread,
253            &sched_actions,
254            &current_time);
255         if (!sched_actions.rejected) {
256           // create a memory area for the explicit messages
257           call_info=(struct explicit_call_info *)
258             malloc(sizeof(struct explicit_call_info));
259           if (call_info==NULL) {
260             CHK(posix_appsched_actions_addreject
261                 (&(sched_actions.actions),event.thread));
262           } else {
263             CHK(posix_appsched_actions_addaccept
264                 (&(sched_actions.actions),event.thread));
265             // store the memory area in thread-specific data
266             CHK(pthread_setspecific_for
267                 (schedthreaddata.msg_key,event.thread,call_info));
268             // activate the thread unless suspended or already activated
269             if (!sched_actions.suspended && !sched_actions.activated) {
270               CHK(posix_appsched_actions_addactivate
271                   (&(sched_actions.actions),event.thread));
272             }
273           }
274         }
275         break;
276       case POSIX_APPSCHED_TERMINATE:
277         sch_thread_data->scheduler_ops.thread_terminate
278           (scheduler_data,
279            event.thread,
280            &sched_actions,
281            &current_time);
282         break;
283       case POSIX_APPSCHED_READY:
284         sch_thread_data->scheduler_ops.thread_ready
285           (scheduler_data,
286            event.thread,
287            &sched_actions,
288            &current_time);
289         // activate the thread unless suspended or already activated
290         if (!sched_actions.suspended && !sched_actions.activated) {
291           CHK(posix_appsched_actions_addactivate
292               (&(sched_actions.actions),event.thread));
293         }
294         break;
295       case POSIX_APPSCHED_BLOCK:
296         sch_thread_data->scheduler_ops.thread_block
297           (scheduler_data,
298            event.thread,
299            &sched_actions,
300            &current_time);
301         break;
302       case POSIX_APPSCHED_CHANGE_SCHED_PARAM:
303         sch_thread_data->scheduler_ops.change_sched_param_thread
304           (scheduler_data,
305            event.thread,
306            &sched_actions,
307            &current_time);
308         break;
309         //case POSIX_APPSCHED_EXPLICIT_CALL_WITH_DATA:
310         //sch_thread_data->scheduler_ops.explicit_call_with_data
311         //  (scheduler_data,
312         //   event.thread,
313         //   event.event_info.info,event.info_size,
314         //   &reply, &reply_size,
315         //   &sched_actions,
316         //   &current_time);
317
318       case POSIX_APPSCHED_EXPLICIT_CALL:
319         CHK(pthread_getspecific_from
320             (schedthreaddata.msg_key,event.thread,(void **)(&call_info)));
321         sch_thread_data->scheduler_ops.explicit_call_with_data
322           (scheduler_data,
323            event.thread,
324            call_info->info_ptr,
325            call_info->info_size,
326            call_info->reply_ptr,
327            &(call_info->reply_size),
328            &sched_actions,
329            &current_time);
330         // activate the thread unless suspended or already activated
331         if (!sched_actions.suspended && !sched_actions.activated) {
332           CHK(posix_appsched_actions_addactivate
333               (&(sched_actions.actions),event.thread));
334         }
335         break;
336       case POSIX_APPSCHED_TASK_NOTIFICATION:
337         clk=(clockid_t) pthread_getspecific(sch_thread_data->clock_key);
338         sch_thread_data->scheduler_ops.notification_for_thread
339           (scheduler_data,
340            event.thread,
341            clk,
342            &sched_actions,
343            &current_time);
344         // t.b.d. check if state of thread is suspended by default
345         break;
346       case POSIX_APPSCHED_TIMEOUT:
347         sch_thread_data->scheduler_ops.timeout
348           (scheduler_data,
349            &sched_actions,
350            &current_time);
351         break;
352       case POSIX_APPSCHED_SIGNAL:
353         sch_thread_data->scheduler_ops.signal
354           (scheduler_data,
355            event.event_info.siginfo.si_signo,
356            *((frsh_signal_info_t *) (&(event.event_info.siginfo.si_value))),
357            // the above casting construct is used to overcome the compiler
358            // restriction that does not allow casts between unions
359            &sched_actions,
360            &current_time);
361         break;
362     default:
363       ASSERT_INFO(true,"Unexpected scheduling event received in scheduler");
364     } // end switch on event code
365   } // end of main scheduler loop
366
367 }
368
369
370 /**
371  * fosa_ads_scheduler_create()
372  *
373  * Create the application defined scheduler
374  *
375  * The application defined scheduler is created with the primitive
376  * operations specified in the object pointed to by scheduler_ops.
377  *
378  * The clock used to read the time immediately before the invocation
379  * of each primitive operation, to be reported to the scheduler via
380  * the current_time parameter of each primitive operation is the
381  * FOSA_CLOCK_REALTIME clock.
382  *
383  * The scheduler_data_size parameter is used to request that a memory
384  * area of this size must be created and reserved for the scheduler to
385  * store its state. A pointer to this area is passed to the scheduler
386  * operations in the sched_data parameter.
387  *
388  * Parameter init_arg points to an area that contains configuration
389  * information for the scheduler. The function creates a memory area
390  * of init_arg_size bytes and copies into it the area pointed by
391  * arg. A pointer to this new created area will be passed to the
392  * primitive operation init() in its arg parameter.
393  *
394  * Returns 0 if successful; otherwise it returns an error code:
395  *     EINVAL: The value of scheduler_ops was invalid
396  *     EAGAIN: The system lacks enough resources to create the scheduler
397  *
398  * Alternatively, in case of error the implementation is allowed to
399  * notify it to the system console and then terminate the FRSH
400  * implementation and dependant applications
401  *
402  * The fosa_ads_scheduler_create function must be called before any
403  * other function in this header file
404  **/
405 int fosa_ads_scheduler_create
406      (const fosa_ads_scheduler_ops_t * scheduler_ops,
407       size_t scheduler_data_size,
408       void * init_args,
409       size_t init_args_size)
410 {
411   pthread_attr_t attr;
412   pthread_mutexattr_t mattr;
413   int err;
414   struct sched_param param;
415
416 #ifdef FULL_ERROR_CHECKING
417   // check for NULL scheduler operations
418   if (scheduler_ops==NULL) {
419     return EINVAL;
420   }
421 #endif   // end if FULL_ERROR_CHECKING
422
423   // copy arguments in scheduler data
424   schedthreaddata.scheduler_ops=*scheduler_ops;
425   schedthreaddata.scheduler_data_size=scheduler_data_size;
426   schedthreaddata.init_args_size=init_args_size;
427
428   // create scheduler memory area
429   schedthreaddata.scheduler_data=malloc(scheduler_data_size);
430   if (schedthreaddata.scheduler_data==NULL) {
431     return EAGAIN;
432   }
433
434   // create init args memory area and copy the init args
435   schedthreaddata.init_args=malloc(init_args_size);
436   if (schedthreaddata.init_args==NULL) {
437     return EAGAIN;
438   }
439   memcpy(schedthreaddata.init_args,init_args,init_args_size);
440
441   // initialize the set of signals used by the scheduler to none
442   CHKE(sigemptyset(&(schedthreaddata.sch_signal_set)));
443
444   // initialize the mutex used to share data with the scheduler
445   CHK(pthread_mutexattr_init(&mattr));
446   // we use the priority protect protocol
447   CHK(pthread_mutexattr_setprotocol(&mattr,PTHREAD_PRIO_PROTECT));
448   // calculate the priority and set priority ceiling
449   param.sched_priority=sched_get_priority_max(SCHED_FIFO)-
450     FOSA_ADS_SCHEDULER_PRIO_DIFF;
451   CHK(pthread_mutexattr_setprioceiling(&mattr,param.sched_priority));
452   // initialize mutex
453   CHK(pthread_mutex_init(&(schedthreaddata.sch_mutex),&mattr));
454   CHK(pthread_mutexattr_destroy(&mattr));
455
456   // create the thread-specific data key for the clock id
457   CHK(pthread_key_create(&schedthreaddata.clock_key,NULL));
458
459   // create the thread-specific data key for the message pointers
460   CHK(pthread_key_create(&schedthreaddata.msg_key,NULL));
461
462   // set the attributes for the scheduler thread
463   err=pthread_attr_init(&attr);
464   if (err!=0) {
465     return err;
466   }
467   CHK(pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED));
468   CHK(pthread_attr_setinheritsched(&attr,PTHREAD_EXPLICIT_SCHED));
469   CHK(pthread_attr_setinheritsched(&attr,PTHREAD_EXPLICIT_SCHED));
470   CHK(pthread_attr_setschedpolicy(&attr,SCHED_FIFO));
471   CHK(pthread_attr_setschedparam(&attr,&param));
472   CHK(pthread_attr_setappschedulerstate(&attr,PTHREAD_APPSCHEDULER));
473   CHK(pthread_attr_setpreemptionlevel(&attr,FOSA_ADS_SCHEDULER_LEVEL));
474
475   // create the scheduler thread
476   return pthread_create(&scheduler_thread_id,&attr,
477                         scheduler_thread_code, (void *) &schedthreaddata);
478 }
479
480 /**
481  * fosa_thread_attr_set_appscheduled()
482  *
483  * Set the appscheduled attribute of a thread attributes object
484  *
485  * This function is used to set the appscheduled attribute in the
486  * object pointed to by attr. This attribute controls the kind of
487  * scheduling used for threads created with it. If true, the thread is
488  * scheduled by the application scheduler. If not, it is scheduled by
489  * the system under a fixed priority scheduler
490  *
491  * Returns 0 if successful; otherwise it returns an error code:
492  *     EINVAL: The value of attr is invalid
493  *
494  * Alternatively, in case of error the implementation is allowed to
495  * notify it to the system console and then terminate the FRSH
496  * implementation and dependant applications
497  **/
498 int fosa_thread_attr_set_appscheduled
499         (frsh_thread_attr_t *attr,
500          bool appscheduled)
501 {
502     int error_code;
503
504     // set the application-defined scheduler thread
505     error_code=pthread_attr_setappscheduler(attr,scheduler_thread_id);
506     if (error_code!=0) return error_code;
507
508     if (appscheduled) {
509         return pthread_attr_setschedpolicy(attr,SCHED_APP);
510     } else {
511         return pthread_attr_setschedpolicy(attr,SCHED_FIFO);
512     }
513 }
514
515 /**
516  * fosa_thread_attr_get_appscheduled()
517  *
518  * Get the appscheduled attribute of a thread attributes object
519  *
520  * This function is used to get the appscheduled attribute in the
521  * object pointed to by attr. This attribute controls the kind of
522  * scheduling used for threads created with it. If true, the thread is
523  * scheduled by the application scheduler. If not, it is scheduled by
524  * the system under a fixed priority scheduler.
525  *
526  * Returns 0 if successful; otherwise it returns an error code:
527  *    EINVAL: The value of attr is invalid
528  *
529  * Alternatively, in case of error the implementation is allowed to
530  * notify it to the system console and then terminate the FRSH
531  * implementation and dependant applications
532  **/
533 int fosa_thread_attr_get_appscheduled
534         (const frsh_thread_attr_t *attr,
535          bool *appscheduled)
536 {
537   int policy, ret_value;
538
539   ret_value=pthread_attr_getschedpolicy(attr,&policy);
540   if (ret_value==0) {
541     if (policy==SCHED_APP) {
542       *appscheduled=true;
543     } else {
544       *appscheduled=false;
545     }
546   }
547   return ret_value;
548 }
549
550 /**
551  * fosa_thread_attr_set_appsched_params()
552  *
553  * Set the appsched_param attribute of a thread attributes object
554  *
555  * This function is used to set the appsched_param attribute in the
556  * object pointed to by attr.  For those threads with appscheduled set
557  * to true, this attribute represents the application-specific
558  * scheduling parameters. If successful, the function shall set the
559  * size of the appsched_param attribute to the value specified by
560  * paramsize, and shall copy the scheduling parameters occupying
561  * paramsize bytes and pointed to by param into that attribute
562  *
563  * Returns 0 if successful; otherwise it returns an error code:
564  *    EINVAL: The value of attr is invalid, or paramsize is less than
565  *            zero or larger than FOSA_ADS_SCHEDPARAM_MAX
566  *
567  * Alternatively, in case of error the implementation is allowed to
568  * notify it to the system console and then terminate the FRSH
569  * implementation and dependant applications
570  **/
571 int fosa_thread_attr_set_appsched_params
572         (frsh_thread_attr_t *attr,
573          const void *param,
574          size_t paramsize)
575 {
576   return pthread_attr_setappschedparam(attr,param,paramsize);
577 }
578
579 /**
580  * fosa_thread_attr_get_appsched_params()
581  *
582  * Get the appsched_param attribute of a thread attributes object
583  *
584  * This function is used to get the appsched_param attribute from the
585  * object pointed to by attr.  For those threads with appscheduled set
586  * to true, this attribute represents the application-specific
587  * scheduling parameters. If successful, the function shall set the
588  * value pointed to by paramsize to the size of the appsched_param
589  * attribute, and shall copy the scheduling parameters occupying
590  * paramsize bytes into the variable pointed to by param. This
591  * variable should be capable of storing a number of bytes equal to
592  * paramsize.
593  *
594  * Returns 0 if successful; otherwise it returns an error code:
595  *     EINVAL: The value of attr is invalid
596  *
597  * Alternatively, in case of error the implementation is allowed to
598  * notify it to the system console and then terminate the FRSH
599  * implementation and dependant applications
600  **/
601 int fosa_thread_attr_get_appsched_params
602         (const frsh_thread_attr_t *attr,
603          void *param,
604          size_t *paramsize)
605 {
606   return pthread_attr_getappschedparam(attr,param,paramsize);
607 }
608
609 /**
610  * fosa_ads_set_appscheduled()
611  *
612  * Dynamically set the appscheduled attribute of a thread
613  *
614  * This function is used to dynamically set the appscheduled attribute
615  * of the thread identified by thread. This attribute controls the
616  * kind of scheduling used for threads created with it. If true, the
617  * thread is scheduled by the application scheduler. If not, it is
618  * scheduled by the system under a fixed priority scheduler.
619  *
620  * Returns 0 if successful; otherwise it returns an error code:
621  *     EINVAL: The value of thread is invalid
622  *
623  *     EREJECT: the attachment of the thread to the frsh schehduler
624  *     was rejected by the frsh scheduler possibly because of
625  *     incorrect attributes, or because the requested minimum
626  *     capacity cannot be guaranteed
627  *
628  * Alternatively, in case of error the implementation is allowed to
629  * notify it to the system console and then terminate the FRSH
630  * implementation and dependant applications
631  **/
632 int fosa_ads_set_appscheduled
633         (frsh_thread_id_t thread,
634          bool appscheduled)
635 {
636    int error_code = 0;
637    int current_policy, new_policy;
638    struct sched_param param;
639
640    // switch to the appropriate scheduling policy
641    CHK(pthread_getschedparam(thread,&current_policy,&param));
642    if (((current_policy==SCHED_APP) && (!appscheduled)) ||
643       ((current_policy!=SCHED_APP) && appscheduled)) {
644       if (appscheduled) {
645          new_policy=SCHED_APP;
646          // set the application-defined scheduler thread
647          error_code=pthread_setappscheduler(thread,scheduler_thread_id);
648          if (error_code!=0) return error_code;
649       } else {
650          new_policy=SCHED_FIFO;
651       }
652       error_code=pthread_setschedparam(thread,new_policy,&param);
653    }
654    return error_code;
655 }
656
657 /**
658  * fosa_ads_getappscheduled()
659  *
660  * Dynamically get the appscheduled attribute of a thread
661  *
662  * This function is used to dynamically get the appscheduled attribute
663  * of the thread identified by thread. This attribute controls the
664  * kind of scheduling used for threads created with it. If true, the
665  * thread is scheduled by the application scheduler. If not, it is
666  * scheduled by the system under a fixed priority scheduler
667  *
668  * Returns 0 if successful; otherwise it returns an error code:
669  *     EINVAL: The value of thread is invalid
670  *
671  * Alternatively, in case of error the implementation is allowed to
672  * notify it to the system console and then terminate the FRSH
673  * implementation and dependant applications
674  **/
675 int fosa_ads_get_appscheduled
676         (frsh_thread_id_t thread,
677          bool *appscheduled)
678 {
679   int error_code, policy;
680   struct sched_param param;
681
682   error_code=pthread_getschedparam(thread,&policy,&param);
683   if (error_code!=0) {
684     return error_code;
685   } else {
686      *appscheduled = (policy==SCHED_APP);
687      return 0;
688   }
689 }
690
691
692 /**
693  * fosa_ads_setappschedparam()
694  *
695  * Dynamically set the appsched_param attribute of a thread
696  *
697  * This function is used to dynamically set the appsched_param
698  * attribute of the thread identified by thread.  For those threads
699  * with appscheduled set to true, this attribute represents the
700  * application-specific scheduling parameters. If successful, the
701  * function shall set the size of the appsched_param attribute to the
702  * value specified by paramsize, and shall copy the scheduling
703  * parameters occupying paramsize bytes and pointed to by param into
704  * that attribute
705  *
706  * Returns 0 if successful; otherwise it returns an error code:
707  *    EINVAL: The value of thread is invalid, or paramsize is less than
708  *            zero or larger than FOSA_ADS_SCHEDPARAM_MAX
709  *
710  * Alternatively, in case of error the implementation is allowed to
711  * notify it to the system console and then terminate the FRSH
712  * implementation and dependant applications
713  **/
714 int fosa_ads_set_appsched_params
715         (frsh_thread_id_t thread,
716          const void *param,
717          size_t paramsize)
718 {
719   return pthread_setappschedparam(thread,param,paramsize);
720 }
721
722 /**
723  * fosa_ads_get_appsched_params()
724  *
725  * Dynamically get the appsched_param attribute of a thread
726  *
727  * This function is used to dynamically get the appsched_param
728  * attribute of the thread identified by thread.  For those threads
729  * with appscheduled set to true, this attribute represents the
730  * application-specific scheduling parameters. If successful, the
731  * function shall set the variable pointed to by paramsize to the size
732  * of the appsched_param attribute, and shall copy the scheduling
733  * parameters occupying paramsize bytes into the variable pointed to
734  * by param. This variable should be capable of storing a number of
735  * bytes equal to paramsize.
736  *
737  *  Returns 0 if successful; otherwise it returns an error code:
738  *     EINVAL: The value of thread is invalid, or paramsize is less than
739  *             zero or larger than FOSA_ADS_SCHEDPARAM_MAX
740  *
741  * Alternatively, in case of error the implementation is allowed to
742  * notify it to the system console and then terminate the FRSH
743  * implementation and dependant applications.
744  **/
745 int fosa_ads_get_appsched_params
746         (frsh_thread_id_t thread,
747          void *param,
748          size_t *paramsize)
749 {
750   return pthread_getappschedparam(thread,param,paramsize);
751 }
752
753
754 /*********************************
755  * ADS actions
756  *
757  * A scheduling actions object is used to specify a series of actions
758  * to be performed by the system at the end of a scheduler primitive
759  * operation. The order of the actions added to the object shall be
760  * preserved.
761  *
762  *********************************/
763
764 /**
765  * fosa_adsactions_add_reject()
766  *
767  * Add a reject-thread action
768  *
769  * This function adds a thread-reject action to the object referenced
770  * by sched_actions, that will serve to notify that the thread
771  * identified by thread has not been accepted by the scheduler to be
772  * scheduled by it, possibly because the thread contained invalid
773  * application scheduling attributes, or because there are not enough
774  * resources for the new thread.  At the end of the new_thread()
775  * scheduler primitive operation, the parent of the rejected thread
776  * waiting on a fosa_thread_create() or the rejected thread itself
777  * waiting on a fosa_ads_set_appscheduled() function shall complete the
778  * function with an error code of EREJECT. If no reject-thread action
779  * is added during the new_thread() scheduler primitive operation, the
780  * thread is accepted to be scheduled by the scheduler and the
781  * associated fosa_thread_create() or the fosa_ads_set_appscheduled()
782  * function shall be completed without error. For the function to
783  * succeed, it has to be called from the new_thread() primitive
784  * operation and for the thread that is requesting attachment to the
785  * scheduler.
786  *
787  *  Returns 0 if successful; otherwise it returns an error code:
788  *     ENOMEM: There is insufficient memory to add this action
789  *     FOSA_EPOLICY: The thread specified by thread is not the one requesting
790  *                   attachment to the scheduler, or the function is not being
791  *                   called from the new_thread primitive operation
792  *     EINVAL: The value specified by sched_actions is invalid
793  *
794  * Alternatively, in case of error the implementation is allowed to
795  * notify it to the system console and then terminate the FRSH
796  * implementation and dependant applications
797  **/
798 int fosa_adsactions_add_reject(
799         fosa_ads_actions_t *sched_actions,
800         frsh_thread_id_t thread)
801 {
802 #ifdef FULL_ERROR_CHECKING
803   // check errors
804   if (!pthread_equal(pthread_self(),scheduler_thread_id)) {
805     return FOSA_EPOLICY;
806   }
807 #endif   // end if FULL_ERROR_CHECKING
808
809   sched_actions->rejected=true;
810   return posix_appsched_actions_addreject(&(sched_actions->actions),thread);
811 }
812
813 /**
814  * fosa_adsactions_add_activate()
815  *
816  * Add a thread-activate action
817  *
818  * This function adds a thread-activate action to the object
819  * referenced by sched_actions. In case the thread had been previously
820  * suspended via posix_appsched_actions_addsuspend(), it will be
821  * activated at the end of the primitive operation.
822  *
823  * In those implementations that do not support urgency scheduling,
824  * the urgencu value is ignored. These implementations cannot support
825  * the frsh hierarchical scheduling module.
826  *
827  * In those implementations supporting urgency-scheduling, the action
828  * will cause the change of the urgency of the thread to the value
829  * specified in the urgency argument. Besides, if the thread was
830  * already active at the time the thread-activate action is executed,
831  * the change or urgency will imply a reordering of the thread in its
832  * priority queue, so that for threads of the same priority, those
833  * with more urgency will be scheduled before those of less urgency.
834  *
835  * Returns 0 if successful; otherwise it returns an error code:
836  *     ENOMEM: There is insufficient memory to add this action
837  *     FOSA_EPOLICY: The thread specified by thread has its appscheduled
838  *                   attribute set to false,
839  *     EINVAL: The value specified by sched_actions is invalid
840  *
841  * Alternatively, in case of error the implementation is allowed to
842  * notify it to the system console and then terminate the FRSH
843  * implementation and dependant applications
844  **/
845 int fosa_adsactions_add_activate(
846         fosa_ads_actions_t *sched_actions,
847         frsh_thread_id_t thread,
848         fosa_ads_urgency_t urgency)
849 {
850 #ifdef FULL_ERROR_CHECKING
851   // check errors
852   struct sched_param param;
853   int policy;
854
855   CHK(pthread_getschedparam(thread,&policy,&param));
856   if (policy!=SCHED_APP) {
857     return FOSA_EPOLICY;
858   }
859 #endif   // end if FULL_ERROR_CHECKING
860
861   sched_actions->activated=true;
862   return posix_appsched_actions_addactivate(&(sched_actions->actions),thread);
863 }
864
865 /**
866  * fosa_adsactions_add_suspend()
867  *
868  * Add a thread-suspend action
869  *
870  * This function adds a thread-suspend action to the object referenced
871  * by sched_actions, that will cause the thread identified by thread
872  * to be suspended waiting for a thread-activate action at the end of
873  * the scheduler operation. If the thread was already waiting for a
874  * thread-activate action the thread-suspend action has no effect. It
875  * is an error trying to suspend a thread that is blocked by the
876  * operating system.
877  *
878  *  Returns 0 if successful; otherwise it returns an error code:
879  *     ENOMEM: There is insufficient memory to add this action
880  *     FOSA_EPOLICY: The thread specified by thread has its appscheduled
881  *                   attribute set to false,
882  *     EINVAL: The value specified by sched_actions is invalid
883  *
884  *  Alternatively, in case of error the implementation is allowed to
885  *  notify it to the system console and then terminate the FRSH
886  *  implementation and dependant applications
887  **/
888 int fosa_adsactions_add_suspend(
889         fosa_ads_actions_t *sched_actions,
890         frsh_thread_id_t thread)
891 {
892 #ifdef FULL_ERROR_CHECKING
893   // check errors
894   struct sched_param param;
895   int policy;
896
897   CHK(pthread_getschedparam(thread,&policy,&param));
898   if (policy!=SCHED_APP) {
899     return FOSA_EPOLICY;
900   }
901 #endif   // end if FULL_ERROR_CHECKING
902   sched_actions->suspended=true;
903   return posix_appsched_actions_addsuspend(&(sched_actions->actions),thread);
904 }
905
906 /**
907  * fosa_adsactions_add_timeout()
908  *
909  * Add a timeout action
910  *
911  * This function adds a timeout action to the object referenced by
912  * sched_actions, that will cause the timeout() scheduler operation to
913  * be invoked if no other scheduler operation is invoked before
914  * timeout expires. The timeout shall expire when the clock specified by
915  * clock_id reaches the absolute time specified by the at_time
916  * argument.
917  *
918  *  Returns 0 if successful; otherwise it returns an error code:
919  *     ENOMEM: There is insufficient memory to add this action
920  *     EINVAL: The value specified by sched_actions is invalid
921  *
922  * Alternatively, in case of error the implementation is allowed to
923  * notify it to the system console and then terminate the FRSH
924  * implementation and dependant applications
925  **/
926 int fosa_adsactions_add_timeout(
927         fosa_ads_actions_t *sched_actions,
928         fosa_clock_id_t clock_id,
929         const struct timespec *at_time)
930 {
931   sched_actions->timeout=*at_time;
932   sched_actions->timeout_ptr=&(sched_actions->timeout);
933   return 0;
934 }
935
936 /**
937  * fosa_adsactions_add_thread_notification()
938  *
939  * Add a timed-thread-notification action
940  *
941  * This function adds a thread-notification action associated with the
942  * thread specified in the thread argument that will cause the
943  * notification_for_thread() scheduler operation to be invoked at the
944  * time specified by at_time. This operation shall be invoked when the
945  * clock specified by clock_id reaches the absolute time specified by
946  * the at_time argument. In particular, a cpu-time clock may be used
947  * for parameter clock_id.Only one thread-notification can be active
948  * for each thread and clock. Calling the function shall remove the
949  * former thread-notification, if any, that had been programmed for
950  * the same thread and clock. A value of NULL for parameter at_time is
951  * used to cancel a previous thread-notification, if any, for the
952  * thread specified by thread and the clock specified by clock_id.
953  *
954  *  Returns 0 if successful; otherwise it returns an error code:
955  *     ENOMEM: There is insufficient memory to add this action
956  *     FOSA_EPOLICY: The thread specified by thread has its appscheduled
957  *                   attribute set to false,
958  *     EINVAL: The value specified by sched_actions is invalid
959  *
960  *  Alternatively, in case of error the implementation is allowed to
961  *  notify it to the system console and then terminate the FRSH
962  *  implementation and dependant applications
963  **/
964 int fosa_adsactions_add_thread_notification(
965         fosa_ads_actions_t *sched_actions,
966         frsh_thread_id_t thread,
967         fosa_clock_id_t clock_id,
968         const struct timespec *at_time)
969 {
970 #ifdef FULL_ERROR_CHECKING
971   // check errors
972   struct sched_param param;
973   int policy;
974
975   CHK(pthread_getschedparam(thread,&policy,&param));
976   if (policy!=SCHED_APP) {
977     return FOSA_EPOLICY;
978   }
979 #endif   // end if FULL_ERROR_CHECKING
980
981   // the implementation uses a timer that generates a signal
982   // with the thread id encoded in the signal info
983   // the clock id is stored in thread-specific data
984
985   // store the clock id in thread-specific data
986   CHK(pthread_setspecific(schedthreaddata.clock_key,(void *) clock_id));
987
988   // t.b.d. this function is currently not used,
989   // therefore we don't implement it yet
990   return ENOSYS;
991 }
992
993
994 /**
995  * fosa_ads_set_handled_signal_set()
996  *
997  * Specifiy the set of signals that will be handled by the application
998  * scheduler
999  *
1000  * This function is used to dynamically set the set of signals that
1001  * are handled by the application scheduler.  When a signal included
1002  * in this set is generated, the signal() primitive operation of the
1003  * application scheduler shall be executed. When a signal in tis set
1004  * is generated, it shall always imply the execution of the signal()
1005  * primitive operation, regardless of whether that signal could be
1006  * accepted by some other thread. Once the signal() primitive
1007  * operation is executed the signal is consumed, so no signal handlers
1008  * shall be executed and no threads using a sigwait operation shall
1009  * return for that particular signal instance.  For this function to
1010  * succeed, it has to be called from a primitive operation of a
1011  * scheduler.
1012  *
1013  * Returns 0 if successful; otherwise it returns an error code:
1014  *    FOSA_EPOLICY: The function has not been called from a scheduler
1015  *                  primitive operation
1016  *    EINVAL: The value specified by set is invalid
1017  *
1018  * Alternatively, in case of error the implementation is allowed to
1019  * notify it to the system console and then terminate the FRSH
1020  * implementation and dependant applications
1021  **/
1022 int fosa_ads_set_handled_signal_set(frsh_signal_t set[], int size)
1023 {
1024   int i;
1025
1026 #ifdef FULL_ERROR_CHECKING
1027   // check errors
1028   if (!pthread_equal(pthread_self(),scheduler_thread_id)) {
1029     return FOSA_EPOLICY;
1030   }
1031 #endif   // end if FULL_ERROR_CHECKING
1032   // empty the signal set
1033   CHKE(sigemptyset(&(schedthreaddata.sch_signal_set)));
1034   // loop for all signals in set, to add them to the set of signals used
1035   // by the scheduler
1036   for(i=0;i<size;i++) {
1037     CHKE(sigaddset(&(schedthreaddata.sch_signal_set),set[i]));
1038   }
1039   return 0;
1040 }
1041
1042
1043 /**
1044  * fosa_signal_queue_scheduler()
1045  *
1046  * Queue a signal destinated to the scheduler
1047  *
1048  * This is a special case of fosa_signal_queue() in which the
1049  * destinator is the scheduler itself.  It is needed by the service
1050  * thread to notify the results to the scheduler.
1051  *
1052  * The problem with this case is that, depending on the implementation,
1053  * this call would be translated to a true signal or to a scheduler
1054  * notification message.
1055  *
1056  * Besides for the scheduler we don't have always a destinator
1057  * thread_id needed in frsh_signal_queue for OSE.
1058  *
1059  * So the fosa implementation will solve this issue internally.
1060  * 
1061  * Returns 0 if successful; otherwise it returns an error code:
1062  *     FOSA_EINVAL: the signal specified by signal is not
1063  *              between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
1064  *
1065  *     FOSA_EAGAIN: no resources are available to queue the signal; the
1066  *             maximum number of queued signals has been reached, or a
1067  *             systemwide resource limit has been exceeded
1068  *
1069  * Alternatively, in case of error the implementation is allowed to
1070  * notify it to the system console and then terminate the FRSH
1071  * implementation and dependant applications
1072  **/
1073 int fosa_signal_queue_scheduler(frsh_signal_t signal, frsh_signal_info_t info)
1074 {
1075     /* In MaRTE OS this function is completely equivalent to
1076        fosa_signal_queue, because there is no notion of receiver.
1077     */
1078
1079     frsh_thread_id_t receiver = 0; /* Dummy value, not used by MaRTE OS */
1080     
1081
1082     return fosa_signal_queue(signal, info, receiver);
1083 }
1084
1085
1086 /**
1087  * fosa_ads_invoke_withdata()
1088  *
1089  * Explicitly invoke the scheduler, with data
1090  *
1091  * This function can be used by any thread in the process to invoke
1092  * the ads scheduler or to share data with it.
1093  *
1094  * If successful, the function shall cause the execution of the
1095  * primitive operation explicit_call_with_data() of the ads scheduler
1096  * with its thread parameter equal to the thread ID of the calling
1097  * thread, and its msg_size parameter equal to msg_size. In addition,
1098  * if msg_size is larger than zero, the function shall make available
1099  * to the scheduler a memory area whose contents are identical to the
1100  * memory area pointed to by msg in the msg parameter of the
1101  * explicit_call_with_data() primitive operation (note that copying
1102  * the information is not needed).
1103  *
1104  * The function shall not return until the system has finished
1105  * execution of the explicit_call_with_data() primitive operation. If
1106  * the reply argument is non NULL, the memory area pointed to by the
1107  * reply parameter of explicit_call_with_data() primitive operation is
1108  * copied into the memory area pointed to by reply, and its size is
1109  * copied into the variable pointed to by reply_size. The size of the
1110  * reply information is limited to the value FOSA_ADS_SCHEDINFO_MAX.
1111  *
1112  * The function shall fail if the size specified by msg_size is larger
1113  * than FOSA_ADS_SCHEDINFO_MAX.  The function shall fail if primitive
1114  * operation explicit_call_with_data() is set to NULL for the ads
1115  * scheduler.
1116  *
1117  *  Returns 0 if successful; otherwise it returns an error code:
1118  *     FOSA_EPOLICY: The function been called from inside a scheduler
1119  *                   primitive operation
1120  *     EINVAL: The value of msg_size is less than zero or larger than
1121  *             FOSA_ADS_SCHEDINFO_MAX
1122  *     FOSA_EMASKED: The operation cannot be executed because the primitive
1123  *                   operation explicit_call_with_data() is set to NULL
1124  *
1125  *  Alternatively, in case of error the implementation is allowed to
1126  *  notify it to the system console and then terminate the FRSH
1127  *  implementation and dependant applications
1128  **/
1129 int fosa_ads_invoke_withdata
1130    (const void *msg, size_t msg_size, void *reply, size_t *reply_size)
1131 {
1132   // The corresponding function in MaRTE OS is not yet implemented
1133   // We implement this function by creating a memory area for each thread
1134   // and using the invoke with no data function
1135   struct explicit_call_info * call_info;
1136   int error_code;
1137
1138 #ifdef FULL_ERROR_CHECKING
1139   // check errors
1140   if (pthread_equal(pthread_self(),scheduler_thread_id)) {
1141     return FOSA_EPOLICY;
1142   }
1143   if (msg_size>FOSA_ADS_SCHEDINFO_MAX) {
1144     return EINVAL;
1145   }
1146   if (schedthreaddata.scheduler_ops.explicit_call_with_data==NULL) {
1147     return FOSA_EMASKED;
1148   }
1149 #endif   // end if FULL_ERROR_CHECKING
1150
1151   call_info = (struct explicit_call_info *)
1152     pthread_getspecific(schedthreaddata.msg_key);
1153   ASSERT_INFO(call_info!=NULL,
1154               "Error in access to specific data for explicit call");
1155   if (call_info==NULL) return EINVAL;
1156   call_info->info_size=msg_size;
1157   // the following type cast is to avoid warnings, but should be OK
1158   call_info->info_ptr=(void *)msg;
1159   call_info->reply_ptr=reply;
1160   error_code=posix_appsched_invoke_scheduler(0);
1161   *reply_size=call_info->reply_size;
1162   return error_code;
1163 }