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