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