From: faggioli Date: Thu, 27 Mar 2008 12:41:03 +0000 (+0000) Subject: Keep the FOSA implementation for the AQuoSA platform in touch X-Git-Url: https://rtime.felk.cvut.cz/gitweb/frescor/fosa.git/commitdiff_plain/46da828932c045058077b3d91517e7b29d2a8010 Keep the FOSA implementation for the AQuoSA platform in touch with the phase-II of the project. git-svn-id: http://www.frescor.org/private/svn/frescor/fosa/trunk@1049 35b4ef3e-fd22-0410-ab77-dab3279adceb --- diff --git a/src_aquosa/Makefile b/src_aquosa/Makefile index f9adaab..0e4f352 100644 --- a/src_aquosa/Makefile +++ b/src_aquosa/Makefile @@ -40,7 +40,7 @@ OBJOPT += -fPIC STATIC_NAME = libfosa_qres.a SHARED_NAME = libfosa_qres.so -SRC = fosa_clocks_and_timers.c fosa_threads_and_signals.c fosa_mutexes_and_condvars.c +SRC = fosa_clocks_and_timers.c fosa_threads_and_signals.c fosa_mutexes_and_condvars.c fosa_time.c PUBLIC_H_FOSA = fosa_app_def_sched.h fosa.h fosa_opaque_types.h fosa_clocks_and_timers.h \ fosa_configuration_parameters.h fosa_mutexes_and_condvars.h fosa_threads_and_signals.h \ @@ -65,7 +65,7 @@ all: ../lib/$(STATIC_NAME) ../lib/$(SHARED_NAME) ../lib/$(SHARED_NAME): $(OBJS) @exec echo -n "=> Generating libfosa_qres.so: "; - $(CC) -shared -o $@ $(OBJS) + @$(CC) -shared -o $@ $(OBJS) @exec echo " [OK]" @@ -75,8 +75,8 @@ all: ../lib/$(STATIC_NAME) ../lib/$(SHARED_NAME) ############################################################### %.o: %.c $(PUBLIC_H_FILE_LOCATIONS) $(PRIVATE_H) - @exec echo -n "=> Compiling $<: "; - $(CC) $(CFLAGS) -c $< + @@exec echo -n "=> Compiling $<: "; + @$(CC) $(CFLAGS) -c $< @exec echo " [OK]" # Clean up # diff --git a/src_aquosa/fosa_clocks_and_timers.c b/src_aquosa/fosa_clocks_and_timers.c index 6172c0b..9c7e293 100644 --- a/src_aquosa/fosa_clocks_and_timers.c +++ b/src_aquosa/fosa_clocks_and_timers.c @@ -58,28 +58,27 @@ // FOSA(Frescor Operating System Adaptation layer) //================================================ -#include +#include "fosa_clocks_and_timers.h" /************************* * Timing: Clocks *************************/ int fosa_clock_get_time(fosa_clock_id_t clockid, - struct timespec *current_time) + struct timespec *current_time) { return clock_gettime(clockid, current_time); } int fosa_thread_get_cputime_clock(fosa_thread_id_t tid, - fosa_clock_id_t *clockid) + fosa_clock_id_t *clockid) { if (tid.linux_pid == tid.linux_tid) { - /* we're in a standard UNIX process */ + /* standard UNIX process */ *clockid = FOSA_CLOCK_REALTIME; - return 0; } else - /* we're in a thread */ + /* POSIX thread */ return pthread_getcpuclockid(tid.pthread_id, clockid); } @@ -87,58 +86,194 @@ int fosa_thread_get_cputime_clock(fosa_thread_id_t tid, * Timing: Timers *************************/ +/** + * fosa_create_timer() + * + * Create a one-shot timer + * + * This function creates a timer based on the clock specified by clock, + * and associates to this timer a notification mechanism consisting of + * a signal and associated information. Initially, the timer is in the + * disarmed state, i.e., not counting time. It can be armed to start + * counting time with fosa_timer_arm(). + * + * The function stores the identifier of the newly created timer in the + * variable pointed to by timerid. + * + * When the timer expires, the signal number specified by signal will be + * sent together with the information specified by info, to the thread + * that armed the timer (@see fosa_timer_arm()). + * + * Note that, since this is a POSIX implementation, the signal will be sent + * to any thread waiting fot it (in a given UNIX process). + * No signal-waiting thread or similar strategy is implemented, the specific + * thread can be choosed (for example) by means of the signal number. + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the value of clockid or signal is invalid + * + * EAGAIN: the system lacks enough resources to create the timer + **/ int fosa_timer_create(fosa_clock_id_t clockid, - fosa_signal_t signal, - fosa_signal_info_t info, - fosa_timer_id_t *timerid) + fosa_signal_t signal, + fosa_signal_info_t info, + fosa_timer_id_t *timerid) { struct sigevent event; event.sigev_notify = SIGEV_SIGNAL; event.sigev_signo = signal; - event.sigev_value.sival_int = info.sival_int; + //event.sigev_value.sival_int = info.sival_int; + event.sigev_value = *((union sigval*) &info); return timer_create(clockid, &event, timerid); } -int fosa_timer_delete(fosa_timer_id_t timerid){ - timer_delete(timerid); - return 0; +/** + * fosa_timer_create_with_receiver() + * + * Create a one-shot timer with a specific signal receiver thread + * + * This function creates a timer in the same way as fosa_timer_create, + * except that the signal generated when the timer expires is sent to + * the thread specified by receiver + * + * In this implementation, since in POSIX we can not specify a receiver, + * always returns ENOSYS. + * + * You have to use the "simple" fosa_timer_create. + **/ + int fosa_timer_create_with_receiver(fosa_clock_id_t clockid, + fosa_signal_t signal, + fosa_signal_info_t info, + fosa_timer_id_t *timerid, + fosa_thread_id_t receiver) +{ + /* in POSIX the receiver thread cannot be specified!! */ + //return fosa_timer_create(clockid, signal, info, timerid); + return ENOSYS; +} + + /** + * Delete a timer + * + * The function deletes the timer specified by timerid, which becomes + * unusable. If the timer was armed, it is automatically disarmed before + * deletion. + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the value of timerid is not valid + **/ +int fosa_timer_delete(fosa_timer_id_t timerid) +{ + return timer_delete(timerid); } +/** + * fosa_timer_arm() + * + * Arm a timer + * + * The timer specified by timer is armed and starts counting time. + * + * If abstime is true, the value pointed to by value is the absolute + * time at which the timer will expire. If value specifies a time instant + * in the past, the timer expires immediately. + * + * If abstime is false, the value pointed to by value is the relative interval + * that must elapse for the timer to expire. + * + * In both cases, absolute or relative, the time is measured with the clock + * associated with the timer when it was created. + * + * If the timer was already armed, the previous time or interval is discarded + * and the timer is rearmed with the new value. + * + * When the timer expires, it is disarmed. + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the value of timerid or value is invalid + **/ int fosa_timer_arm (fosa_timer_id_t timerid, - bool abstime, - const struct timespec *value) + bool abstime, + const struct timespec *value) { - int flags; struct itimerspec when; - when.it_value = *value; /* one shot timer */ + /* non-periodic one shot timer configuration */ + when.it_value = *value; when.it_interval.tv_sec = 0; - when.it_interval.tv_nsec = 0; /* no periodic behaviour */ - if (abstime) - flags = TIMER_ABSTIME; - else - flags = 0; + when.it_interval.tv_nsec = 0; - return timer_settime(timerid, flags, &when, NULL); + return timer_settime(timerid, + (abstime ? TIMER_ABSTIME : 0), + &when, + NULL); } -int fosa_timer_get_remaining_time(fosa_timer_id_t timerid, struct timespec *remaining_time) +/** + * fosa_timer_get_remaining_time() + * + * Get the remaining time for timer expiration + * + * Returns the relative remaining time for timer expiration. If the + * clock is a CPU clock it returns the time as if the thread was + * executing constantly. + * + * If the timer is disarmed it returns 0. + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the value of timerid or value is invalid + **/ +int fosa_timer_get_remaining_time(fosa_timer_id_t timerid, + struct timespec *remaining_time) { - errno = EINVAL; - return -1; + int error; + struct itimerspec time; + + if (remaining_time != NULL) { + if ((error = timer_gettime(timerid, &time)) == -1) + return error; + + *remaining_time = time.it_value; + } else + return EINVAL; + + return 0; } -int fosa_timer_disarm(fosa_timer_id_t timerid, struct timespec *remaining_time) +/** + * fosa_timer_disarm() + * + * Disarm a timer + * + * The timer specified by timer is disarmed, and will not expire unless + * it is rearmed. If the timer was already disramed, the function has + * no effect. + * + * If the pointer remaining_time is != NULL, the remaining time before + * expiration will be returned in that pointer. If the timer was + * disarmed a 0 value will be set. + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the value of timerid or value is invalid + **/ +int fosa_timer_disarm(fosa_timer_id_t timerid, + struct timespec *remaining_time) { - struct itimerspec when; + int error; + struct itimerspec time; + + if (remaining_time != NULL) { + if ((error = timer_gettime(timerid, &time)) == -1) + return error; + + *remaining_time = time.it_value; + } - /* maybe not needed but safer */ - when.it_value.tv_sec = 0; - when.it_value.tv_nsec = 0; - when.it_interval = when.it_value; + time.it_value.tv_sec = 0; + time.it_value.tv_nsec = 0; - return timer_settime(timerid, TIMER_ABSTIME , &when, NULL); + return timer_settime(timerid, 0, &time, NULL); } diff --git a/src_aquosa/fosa_mutexes_and_condvars.c b/src_aquosa/fosa_mutexes_and_condvars.c index 05ac5e6..c40e856 100644 --- a/src_aquosa/fosa_mutexes_and_condvars.c +++ b/src_aquosa/fosa_mutexes_and_condvars.c @@ -58,55 +58,140 @@ // FOSA(Frescor Operating System Adaptation layer) //================================================ -#include - +#include "fosa_mutexes_and_condvars.h" /******************************************************* * Mutexes with priority/bandwidth inheritance ******************************************************/ - +/** + * fosa_mutex_init() + * + * Initialize a frsh mutex + * + * The mutex pointed to by mutex is initialized as a mutex using + * the priority ceiling protocol. A priority ceiling of prioceiling + * is assigned to this mutex. + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the value of prioceiling is invalid + * EAGAIN: the system lacked the necessary resources to create the mutex + * ENOMEM: Insufficient memory exists to initialize the mutex + * EBUSY: The system has detected an attempt to reinitialize the mutex + **/ int fosa_mutex_init(fosa_mutex_t *mutex, int prioceiling) { - //pthread_mutexattr_t mutex_attr; - - /* prioceiling serves as a flag */ - /* if (prioceiling) { - pthread_mutexattr_init(&mutex_attr); - pthread_mutexattr_setprotocol(&mutex_attr, PTHREAD_PRIO_INHERIT); - - return pthread_mutex_init(mutex, &mutex_attr); - } else */ - return pthread_mutex_init(mutex, NULL); + int error; + pthread_mutexattr_t attr; + + if ((error = pthread_mutexattr_init(&attr)) != 0) + return error; + + if ((error = pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT)) != 0) + return error; + + return pthread_mutex_init(mutex, &attr); } +/** + * fosa_mutex_destroy() + * + * Destroy a frsh mutex + * + * The mutex pointed to by mutex is destroyed + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the value of mutex is invalid + * EBUSY: The mutex is in use (is locked) + **/ int fosa_mutex_destroy(fosa_mutex_t *mutex) { return pthread_mutex_destroy(mutex); } +/** + * fosa_mutex_set_prioceiling() + * + * Dynamically set the priority ceiling of a mutex + * + * Since in this implementation we use BandWidth Inheritance defining the + * ceiling of a mutex is meaningless, and so the function always returns + * EINVAL + **/ int fosa_mutex_set_prioceiling(fosa_mutex_t *mutex, - int new_ceiling, - int *old_ceiling) + int new_ceiling, + int *old_ceiling) { - return -1; + return -EINVAL; } +/** + * fosa_mutex_get_prioceiling() + * + * Dynamically get the priority ceiling of a mutex + * + * Since in this implementation we use BandWidth Inheritance defining the + * ceiling of a mutex is meaningless, and so the function always returns + * EINVAL + **/ int fosa_mutex_get_prioceiling(const fosa_mutex_t *mutex, int *ceiling) { - return -1; + return -EINVAL; } +/** + * fosa_mutex_lock() + * + * Lock a mutex + * + * This function locks the mutex specified by mutex. If it is already + * locked, the calling thread blocks until the mutex becomes + * available. The operation returns with the mutex in the locked + * state, with the calling thread as its owner. + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the value of mutex is invalid, or the priority of the + * calling thread is higher than the priority ceiling of the mutex + * EDEADLK: the current thread already owns this mutex + **/ int fosa_mutex_lock(fosa_mutex_t *mutex) { return pthread_mutex_lock(mutex); } +/** + * fosa_mutex_trylock() + * + * Try locking a mutex + * + * This function is identical to fosa_mutex_lock() except that if the + * mutex is already locked the call returns immediately with an error + * indication. + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the value of mutex is invalid, or the priority of the + * calling thread is higher than the priority ceiling of the mutex + * EBUSY: the mutex was already locked + **/ int fosa_mutex_trylock(fosa_mutex_t *mutex) { return pthread_mutex_trylock(mutex); } +/** + * fosa_mutex_unlock() + * + * Unlock a mutex + * + * This function must be called by the owner of the mutex referenced + * by mutex, to unlock it. If there are threads blocked on the mutex + * the mutex becomes available and the highest priority thread is + * awakened to acquire the mutex. + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the value of mutex is invalid + * EPERM: the calling thread is not the owner of the mutex + **/ int fosa_mutex_unlock(fosa_mutex_t *mutex) { return pthread_mutex_unlock(mutex); @@ -116,35 +201,116 @@ int fosa_mutex_unlock(fosa_mutex_t *mutex) * Condition variables *********************/ +/** + * fosa_cond_init() + * + * Initiatize a condition variable + * + * The condition variable referenced by cond is initialized with + * the attributes required by the FOSA implementation. + * + * Returns 0 if successful; otherwise it returns an error code: + * EAGAIN: the system lacked the necessary resources to create the + * condition variable + * ENOMEM: Insufficient memory exists to initialize the condition variable + * EBUSY: The system has detected an attempt to reinitialize the + * condition variable + **/ int fosa_cond_init(fosa_cond_t *cond) { return pthread_cond_init(cond, NULL); } +/** + * fosa_cond_destroy() + * + * Destroy a condition variable + * + * The condition variable pointed to by cond is destroyed + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the value of cond is invalid + * EBUSY: The condition variable is in use (a thread is waiting on it) + **/ int fosa_cond_destroy(fosa_cond_t *cond) { return pthread_cond_destroy(cond); } +/** + * fosa_cond_signal() + * + * Signal a condition variable + * + * This call unblocks at least one of the threads that are waiting on + * the condition variable referenced by cond. If there are no threads + * waiting, the function has no effect + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the value of cond is invalid + **/ int fosa_cond_signal(fosa_cond_t *cond) { return pthread_cond_signal(cond); } +/** + * fosa_cond_broadcast() + * + * Broadcast a condition variable + * + * This call unblocks all of the threads that are waiting on the + * condition variable referenced by cond. If there are no threads + * waiting, the function has no effect. + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the value of cond is invalid + **/ int fosa_cond_broadcast(fosa_cond_t *cond) { return pthread_cond_broadcast(cond); } +/** + * fosa_cond_wait() + * + * Wait at a condition variable + * + * This call is used to block on the condition variable referenced by + * cond. It shall be called with the mutex referenced by mutex + * locked. The function releases the mutex and blocks the calling + * thread until the condition is signalled by some other thread and + * the calling thread is awakened. Then it locks the mutex and + * returns with the mutex locked by the calling thread. + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the value of cond or mutex is invalid, or different + * mutexes were used for concurrent wait operations on cond, or + * the mutex was not owned by the calling thread + **/ int fosa_cond_wait(fosa_cond_t *cond, fosa_mutex_t *mutex) { return pthread_cond_wait(cond, mutex); } +/** + * fosa_cond_timedwait() + * + * Wait at a condition variable, with a timeout + * + * This function is equal to fosa_cond_wait(), except that the maximum + * wait time is limited to the absolute time referenced by abstime, as + * measured by the FOSA_CLOCK_ABSOLUTE clock. + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the value of cond or mutex or abstime is invalid, or different + * mutexes were used for concurrent wait operations on cond, or + * the mutex was not owned by the calling thread + * ETIMEDOUT: the timeout expired + **/ int fosa_cond_timedwait(fosa_cond_t *cond, fosa_mutex_t *mutex, const struct timespec *abstime) { return pthread_cond_timedwait(cond, mutex, abstime); } - diff --git a/src_aquosa/fosa_threads_and_signals.c b/src_aquosa/fosa_threads_and_signals.c index d83b7a2..895a567 100644 --- a/src_aquosa/fosa_threads_and_signals.c +++ b/src_aquosa/fosa_threads_and_signals.c @@ -57,59 +57,225 @@ // FOSA(Frescor Operating System Adaptation layer) //================================================ -#include -#include -#include +#include "fosa_threads_and_signals.h" +#include "fosa_configuration_parameters.h" + +/************************* + * Storage of thread-specific keys + *************************/ + +static pthread_key_t key_list[FOSA_MAX_KEYS]; +static bool key_in_use[FOSA_MAX_KEYS]; +static pthread_mutex_t key_lock; + + +/* Initialize the keys data structure */ +int init_keys() +{ + int i, error; + pthread_mutexattr_t attr; + + for(i = 0; i < FOSA_MAX_KEYS; i++) + key_in_use[i] = false; + + if ((error = pthread_mutexattr_init(&attr)) != 0) + return error; + + if ((error = pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT)) != 0) + return error; + + if ((error = pthread_mutex_init(&key_lock,&attr)) != 0) + return error; + + //if ((error = pthread_mutexattr_destroy(&attr)) != 0) + // return error; + + return 0; +} /************************* * Thread identification *************************/ +/** + * fosa_thread_equal() + * + * Compare two thread identifiers to determine if they refer to the + * same thread + **/ bool fosa_thread_equal(fosa_thread_id_t t1, fosa_thread_id_t t2) { - if ( pthread_equal(t1.pthread_id, t2.pthread_id && - t1.linux_pid == t2.linux_pid && - t1.linux_tid == t2.linux_tid) ) - return true; - - return false; + return t1.linux_pid == t2.linux_pid && + t1.linux_tid == t2.linux_tid && + pthread_equal(t1.pthread_id, t2.pthread_id); } +/** + * fosa_thread_self() + * + * Return the thread id of the calling thread + **/ fosa_thread_id_t fosa_thread_self() { fosa_thread_id_t thread_self; - /* - * Fill the user pointer with appropriate data for the calling thread + /** * NB. Remember: * fosa_thread_id_t => struct { * pthread_t pthread_id; * pid_t linux_pid; * tid_t linux_tid; * }; - */ - thread_self.pthread_id = pthread_self(); /* only valid for threads! */ + **/ + thread_self.pthread_id = pthread_self(); thread_self.linux_pid = getpid(); - thread_self.linux_tid = syscall(__NR_gettid); /* equal to gettid() */ + thread_self.linux_tid = syscall(__NR_gettid); /* gettid() */ return thread_self; } +/************************* + * Thread attributes + *************************/ + +/** + * fosa_thread_attr_init() + * + * Initialize a thread attributes object + * + * This function initializes the object pointed to by attr to all + * the default values defined by FRSH + * + * return 0 if successful; otherwise it returns + * FOSA_ENOMEM: insufficient memory exists to initialize the thread + * attributes object + **/ +int fosa_thread_attr_init(fosa_thread_attr_t *attr) +{ + fosa_thread_id_t self; + + /* only POSIX threads have attributes */ + self = fosa_thread_self(); + if (self.linux_pid == self.linux_tid) + return EINVAL; + + return pthread_attr_init(attr); +} + +/** + * fosa_thread_attr_destroy() + * + * Destroy a thread attributes object + * + * This function is used to destroy the thread attributes object, + * pointed to by attr, and deallocate any system resources allocated for it + * + * Returns 0 + */ +int fosa_thread_attr_destroy(fosa_thread_attr_t *attr) +{ + fosa_thread_id_t self; + + /* only POSIX threads can have attributes */ + self = fosa_thread_self(); + if (self.linux_pid == self.linux_tid) + return EINVAL; + + return pthread_attr_destroy(attr); +} + +/** + * fosa_thread_attr_set_stacksize() + * + * Set the thread minimum stack size in a thread attributes object + * + * This function sets the minimum stack size of the thread attributes + * object attr to the value given by stacksize, in bytes. This + * function has no runtime effect on the stack size, except when the + * attributes object is used to create a thread, when it will be + * created with the specified minimum stack size + * + * return 0 if successful, or the following error code: + * FOSA_EINVAL: the specified stacksize value is not supported in + * this implementation + */ +int fosa_thread_attr_set_stacksize(fosa_thread_attr_t *attr, + size_t stacksize) +{ + fosa_thread_id_t self; + + /* only POSIX threads can set the size of the stack */ + self = fosa_thread_self(); + if (self.linux_pid == self.linux_tid) + return EINVAL; + + return pthread_attr_setstacksize(attr, stacksize); +} + +/** + * fosa_thread_attr_get_stacksize() + * + * Get the thread minimum stack size from a thread attributes object + * + * This function sets the variable pointed to by stacksize to the + * minimum stack size stored in the thread attributes object attr. + * + * return 0 + */ +int fosa_thread_attr_get_stacksize(const fosa_thread_attr_t *attr, + size_t *stacksize) +{ + fosa_thread_id_t self; + + /* only POSIX threads can set the size of the stack */ + self = fosa_thread_self(); + if (self.linux_pid == self.linux_tid) + return EINVAL; + + return pthread_attr_getstacksize(attr, stacksize); +} + /************************* * Thread creation and termination - *************************/ + *************************/ +/** + * fosa_thread_create() + * + * This function creates a new thread using the attributes specified + * in attr. If attr is NULL, default attributes are used. The new + * thread starts running immediately, executing the function specified + * by code, with an argument equal to arg. Upon successful return, the + * variable pointed to by tid will contain the identifier of the newly + * created thread. The set of signals that may be synchronously + * accepted is inherited from the parent thread. + * + * Returns 0 if successful; otherwise it returs a code error: + * + * EAGAIN: the system lacks the necessary resources to create a + * new thread or the maximum number of threads has been + * reached + * + * EINVAL: the value specified by attr is invalid (for instance, + * it has not been correctly initialized) + * + * EREJECT: the cretion of the thread was rejected by the frsh scheduler + * possibly because of incorrect attributes, or because the + * requested minimum capacity cannot be guaranteed + **/ int fosa_thread_create(fosa_thread_id_t *tid, - const fosa_thread_attr_t *attr, - fosa_thread_code_t code, - void *arg) + const fosa_thread_attr_t *attr, + fosa_thread_code_t code, + void *arg) { - pthread_t tmp_tid; - - /* 'tid' can't be used, act other ways - * to get the thread id of the new thread */ - return pthread_create(&tmp_tid,attr,code, arg); + return pthread_create(&tid->pthread_id, attr, code, arg); } +/** + * Note: no thread termination primitive is provided. The termination + * of a thread will be notified by the system to the FRSH scheduler + * through the scheduler API + **/ + /************************************************** * Thread-specific data * (extended with access from a different thread) @@ -120,34 +286,140 @@ int fosa_thread_create(fosa_thread_id_t *tid, * deallocating the memory area pointed to by the pointer **************************************************/ -int fosa_thread_set_specific_data(int key, - fosa_thread_id_t tid, - const void *value) +/** + * fosa_key_create() + * + * Create a new key for thread specific data. + * + * Prior to setting data in a key, we need ask the system to create + * one for us. + * + * return 0 if successful \n + * FOSA_EINVAL If we already have reached the FOSA_MAX_KEYS limit. + * FOSA_ENOMEM If there are no enough memory resources to + * create the key. + **/ +int fosa_key_create(int *key) +{ + int i, error = 0; + bool found = false; + fosa_thread_id_t self; + + /* only POSIX threads can have specific data */ + self = fosa_thread_self(); + if (self.linux_pid == self.linux_tid) + return EINVAL; + + if ((error = pthread_mutex_lock(&key_lock)) != 0) + return error; + + /* find an unused key */ + for (i = 0; i < FOSA_MAX_KEYS; i++) { + if (!key_in_use[i]) { + *key = i; + key_in_use[i] = true; + error = pthread_key_create(&(key_list[i]), NULL); + found = true; + break; + } + } + + if ((error = pthread_mutex_unlock(&key_lock))!= 0) + return error; + + return (!found ? FOSA_EINVAL : error); +} + +/** + * fosa_key_destroy() + * + * Destroy a key + * + * This destroys the key and isables its use in the system + * + * return 0 if successful + * FOSA_EINVAL The key is not initialised or is not in FOSA key range. + **/ +int fosa_key_destroy(int key) +{ + int error; + fosa_thread_id_t self; + + /* only POSIX threads can have specific data */ + self = fosa_thread_self(); + if (self.linux_pid == self.linux_tid) + return EINVAL; + + if ((error = pthread_mutex_lock(&key_lock)) != 0) + return error; + + if ((error = pthread_key_delete(key_list[key])) != 0) + key_in_use[key]=false; + + if ((error = pthread_mutex_unlock(&key_lock)) != 0) + return error; + + return 0; +} + + +/** + * fosa_thread_set_specific_data() + * + * Set thread-specific data + * + * For the thread identified by tid, the thread-specifid data field + * identified by key will be set to the value specified by value + * + * In this implementation, according to POSIX, the accessed data field + * is the one of the calling thread, not the one specified via tid. + * + * Returns 0 if successful; otherwise, an error code is returned + * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1 + **/ + int fosa_thread_set_specific_data(int key, + fosa_thread_id_t tid, + const void * value) { - //if ((key > 0) && (key < (FOSA_MAX_KEYS-1))) { - // tid.pthread_id->tsd[key] = (void *) value; - // - // return 0; - //} - - errno = EINVAL; - return -1; + fosa_thread_id_t self; + + /* only POSIX threads can have specific data */ + self = fosa_thread_self(); + if (self.linux_pid == self.linux_tid) + return EINVAL; + + return pthread_setspecific(key_list[key], value); } +/** + * fosa_thread_get_specific_data() + * + * Get thread-specific data + * + * For the thread identified by tid, the thread-specifid data field + * identified by key will be copied to the variable pointed to by value + * + * In this implementation, according to POSIX, the accessed data field + * is the one of the calling thread, not the one specified via tid. + * + * Returns 0 if successful; otherwise, an error code is returned + * EINVAL: the value of key is not between 0 and FOSA_MAX_KEYS-1 + **/ int fosa_thread_get_specific_data(int key, - fosa_thread_id_t tid, - void **value) + fosa_thread_id_t tid, + void ** value) { - //if ((key > 0) && (key < (FOSA_MAX_KEYS-1))) { - // *value=pthread_remote_getspecific(key,tid); - // *value=tid.pthread_id->tsd[key]; - // - // return 0; - //} + fosa_thread_id_t self; - errno = EINVAL; - return -1; + /* only POSIX threads can have specific data */ + self = fosa_thread_self(); + if (self.linux_pid == self.linux_tid) + return EINVAL; + if ((value = pthread_getspecific(key_list[key])) != NULL) + return EINVAL; + else + return 0; } /****************************************************************** @@ -161,53 +433,140 @@ int fosa_thread_get_specific_data(int key, * mapping is automatically provided by the OS adaptation layer. *******************************************************************/ -int fosa_get_priority_max() { - return sched_get_priority_max(0); +/** + * fosa_get_priority_max() + * + * Return the maximum priority value used in this implementation + **/ +int fosa_get_priority_max() +{ + return sched_get_priority_max(SCHED_FIFO); } -int fosa_get_priority_min() { - return sched_get_priority_min(0); +/** + * fosa_get_priority_min() + * + * Return the minimum priority value used in this implementation + **/ +int fosa_get_priority_min() +{ + return sched_get_priority_min(SCHED_FIFO); } +/** + * fosa_thread_attr_set_prio() + * + * Change the priority of a thread attributes object + * + * The priority of the thread attriutes object specified by attr is + * set to the value specified by prio. This function has no runtime + * effect on the priority, except when the attributes object is used + * to create a thread, when it will be created with the specified + * priority + * + * Returns 0 if successful, or the following error code: + * EINVAL: the specified priority value is not between the + * minimum and the maximum priorities defined in this + * FRSH implementation + **/ int fosa_thread_attr_set_prio(fosa_thread_attr_t *attr, int prio) { - //if ((sched_get_priority_min(0)<=prio) || (prio<=sched_get_priority_min(0))) { - // attr->sched_param.sched_priority = prio; - // - // return 0; - //} - - errno = EINVAL; - return -1; + fosa_thread_id_t self; + struct sched_param param; + + /* normal UNIX processes have no attributes */ + self = fosa_thread_self(); + if (self.linux_pid == self.linux_tid) + return EINVAL; + + param.sched_priority = prio; + + return pthread_attr_setschedparam(attr, ¶m); } -int fosa_thread_attr_get_prio (const fosa_thread_attr_t *attr, int *prio) +/** + * fosa_thread_attr_get_prio() + * + * Get the priority from a thread attributes object + * + * This function sets the variable pointed to by prio to the + * priority stored in the thread attributes object attr. + * + * Returns 0 + **/ +int fosa_thread_attr_get_prio(const fosa_thread_attr_t *attr, int *prio) { - //*prio = attr->sched_param.sched_priority; - //return 0; + int error; + fosa_thread_id_t self; + struct sched_param param; + + /* normal UNIX processes have no attributes */ + self = fosa_thread_self(); + if (self.linux_pid == self.linux_tid) + return EINVAL; - errno = EINVAL; - return -1; + if ((error = pthread_attr_getschedparam(attr, ¶m)) == 0) + *prio = param.sched_priority; + + return error; } +/** + * fosa_thread_set_prio() + * + * Dynamically change the priority of a thread + * + * The priority of the thread identified by tid is + * set to the value specified by prio. + * + * Returns 0 if successful, or the following error code: + * EINVAL: the specified priority value is not between the + * minimum and the maximum priorities defined in this + * FRSH implementation + **/ int fosa_thread_set_prio(fosa_thread_id_t tid, int prio) { - //if ((sched_get_priority_min(0)<=prio) || (prio<=sched_get_priority_min(0))) { - // pthread_setschedprio(tid.pthread_id,prio); - // return 0; - //} - - errno = EINVAL; - return -1; + struct sched_param param; + int error; + + param.sched_priority=prio; + if (tid.linux_pid == tid.linux_tid) + error = sched_setscheduler(tid.linux_pid, + SCHED_RR, + ¶m); + else + error = pthread_setschedparam(tid.pthread_id, + SCHED_RR, + ¶m); + + return error; } +/** + * fosa_thread_get_prio() + * + * Dynamically get the priority of a thread + * + * This function sets the variable pointed to by prio to the + * priority of the thread identified by tid + * + * Returns 0 + **/ int fosa_thread_get_prio (fosa_thread_id_t tid, int *prio) { - //*prio = tid.pthread_id->sched_param.sched_priority; - //return 0; + struct sched_param param; + int policy, error; + + if (tid.linux_pid == tid.linux_tid) + error = sched_getparam(tid.linux_pid, ¶m); + else + error = pthread_getschedparam(tid.pthread_id, + &policy, + ¶m); - errno = EINVAL; - return -1; + *prio = param.sched_priority; + + return error; } /******************************************************************* @@ -223,86 +582,167 @@ int fosa_thread_get_prio (fosa_thread_id_t tid, int *prio) * values. *******************************************************************/ -/* it's an hack and it does not work! - * We need to change the API if we want such a feature!!*/ -sigset_t original_mask; - +/** + * fosa_set_accepted_signals() + * + * Establish the set of signals that may be synchronously accepted + * by the calling thread + * + * The function uses the array of signal numbers specified by set, + * which must be of size equal to size + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the array contains one or more values which are not + * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size + * is less than 0 + **/ int fosa_set_accepted_signals(fosa_signal_t set[], int size) { - int x; - sigset_t new_mask; - - /* all signal blocked by default */ - sigfillset(&new_mask); - for (x = 0; x < size; x++) - /* unblock only the signals in 'set' */ - sigdelset(&new_mask, set[x]); - - /* NB. save the original mask in the - * default variable... Orrible hack!! :-( */ - return pthread_sigmask(SIG_SETMASK, &new_mask, &original_mask); + int i, error; + fosa_thread_id_t self; + sigset_t sigset; + struct sigaction action; + + if ((error = sigemptyset(&sigset)) != 0) + return error; + + /* real-time signal (can be queued) */ + action.sa_handler = SIG_DFL; + action.sa_mask = sigset; + action.sa_flags = SA_SIGINFO; + action.sa_sigaction = NULL; + + for (i = 0; i < size; i++) { + if ((error = sigaddset(&sigset, set[i])) != 0) + return error; + if ((error = sigaction(set[i], &action, NULL)) != 0) + return error; + } + + self = fosa_thread_self(); + if (self.linux_pid == self.linux_tid) + return pthread_sigmask(SIG_BLOCK, &sigset, NULL); + else + return sigprocmask(SIG_BLOCK, &sigset, NULL); } +/** + * fosa_signal_queue() + * + * Queue a signal + * + * This function is used to explicitly send a signal with a specified + * value + * + * The signal number specified by signal is sent together with the + * information specified by info, to the thread identified by + * receiver. + * + * Note that, in this implementation, the signal is sent to any thread + * waiting for it (maybe via fosa_signal_wait()). + * If needed ensure the receiver is the only one who is waiting for the + * signal (e.g., by using different signal numbers for each thread). + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the signal specified by signal is not + * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX + * + * EAGAIN: no resources are available to queue the signal; the + * maximum number of queued signals has been reached, or a + * systemwide resource limit has been exceeded + **/ int fosa_signal_queue(fosa_signal_t signal, - fosa_signal_info_t info, - fosa_thread_id_t receiver) + fosa_signal_info_t info, + fosa_thread_id_t receiver) { - union sigval siginfo; - - siginfo.sival_int = info.sival_int; - return sigqueue(receiver.linux_pid, signal, siginfo); + /* Note: signal sent to a "whole" process */ + return sigqueue(receiver.linux_pid, signal, *((union sigval*) &info)); } -int fosa_signal_wait (fosa_signal_t set[], - int size, - fosa_signal_t *signal_received, - fosa_signal_info_t *info) +/** + * fosa_signal_wait() + * + * Wait for a signal + * + * The function waits for the arrival of one of the signals in the + * array of signal numbers specified by set, which must be of size + * equal to size. If there is a signal already queued, the function + * returns immediately. If there is no signal of the specified set + * queued, the calling thread is suspended until a signal from that + * set arrives. Upon return, if signal_received is not NULL the number + * of the signal received is stored in the variable pointed to by + * signal_received; and if info is not NULL the associated information + * is stored in the variable pointed to by info. + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the array contains one or more values which are not + * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size + * is less than 0 + **/ +int fosa_signal_wait(fosa_signal_t set[], int size, + fosa_signal_t *signal_received, + fosa_signal_info_t *info) { - int x; - sigset_t wait_mask; - siginfo_t recv_signal_info; - - /* only wait for the signals in 'set' */ - sigemptyset(&wait_mask); - for (x = 0; x < size; x++) - sigaddset(&wait_mask, set[x]); - /* go to sleep and let's hope someone wake up us !! */ - if (sigwaitinfo(&wait_mask, &recv_signal_info) < 0) - return -1; - /* return back informations for the caller */ - *signal_received = recv_signal_info.si_signo; - info->sival_int = recv_signal_info.si_value.sival_int; - /* reset the signal mask to original one (orrible hack!!) */ - pthread_sigmask(SIG_SETMASK, &original_mask, NULL); + int i, error; + sigset_t sigset; + siginfo_t siginfo; + + if ((error = sigemptyset(&sigset)) != 0) + return error; + + for (i = 0; i < size; i++) + if ((error = sigaddset(&sigset,set[i])) != 0) + return error; + + if ((error = sigwaitinfo(&sigset, &siginfo)) != 0) + return error; + + if (signal_received != NULL) + *signal_received = siginfo.si_signo; + if (info != NULL) + *info = (fosa_signal_info_t) siginfo.si_value.sival_int; return 0; } -int fosa_signal_timedwait(fosa_signal_t set[], - int size, - fosa_signal_t *signal_received, - fosa_signal_info_t *info, - const struct timespec *timeout) +/** + * fosa_signal_timedwait() + * + * Timed wait for a signal + * + * This function behaves the same as fosa_signal_wait(), except that + * the suspension time is limited to the time interval specified in + * the timespec structure referenced by timeout. + * + * Returns 0 if successful; otherwise it returns an error code: + * EINVAL: the array contains one or more values which are not + * between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX, or size + * is less than 0, or timeout is invalid + * EAGAIN: The timeout expired + **/ +int fosa_signal_timedwait(fosa_signal_t set[], int size, + fosa_signal_t *signal_received, + fosa_signal_info_t *info, + const struct timespec *timeout) { - int x; - sigset_t wait_mask; - siginfo_t recv_signal_info; - - /* only wait for the signals in 'set' */ - sigemptyset(&wait_mask); - for (x = 0; x < size; x++) - sigaddset(&wait_mask, set[x]); - /* go to sleep and let's hope someone wake up us !! */ - if (sigtimedwait(&wait_mask, &recv_signal_info, timeout) < 0) - return -1; - /* return back informations for the caller */ + int i, error; + sigset_t signalset; + siginfo_t siginfo; + + if ((error = sigemptyset(&signalset)) != 0) + return error; + + for (i = 0; i < size; i++) + if ((error = sigaddset(&signalset,set[i])) != 0) + return error; + + if ((error = sigtimedwait(&signalset,&siginfo,timeout)) != 0) + return error; + if (signal_received != NULL) - *signal_received = recv_signal_info.si_signo; + *signal_received = siginfo.si_signo; if (info != NULL) - info->sival_int = recv_signal_info.si_value.sival_int; - /* reset the signal mask to original one (orrible hack!!) */ - pthread_sigmask(SIG_SETMASK, &original_mask, NULL); + *info = (fosa_signal_info_t) siginfo.si_value.sival_int; - return 0; + return 0; } - diff --git a/src_aquosa/fosa_time.c b/src_aquosa/fosa_time.c new file mode 100644 index 0000000..07c312d --- /dev/null +++ b/src_aquosa/fosa_time.c @@ -0,0 +1,110 @@ +//---------------------------------------------------------------------- +// Copyright (C) 2006 - 2007 by the FRESCOR consortium: +// +// Universidad de Cantabria, SPAIN +// University of York, UK +// Scuola Superiore Sant'Anna, ITALY +// Kaiserslautern University, GERMANY +// Univ. Politecnica Valencia, SPAIN +// Czech Technical University in Prague, CZECH REPUBLIC +// ENEA SWEDEN +// Thales Communication S.A. FRANCE +// Visual Tools S.A. SPAIN +// Rapita Systems Ltd UK +// Evidence ITALY +// +// See http://www.frescor.org +// +// The FRESCOR project (FP6/2005/IST/5-034026) is funded +// in part by the European Union Sixth Framework Programme +// The European Union is not liable of any use that may be +// made of this code. +// +// +// based on previous work (FSF) done in the FIRST project +// +// Copyright (C) 2005 Mälardalen University, SWEDEN +// Scuola Superiore S.Anna, ITALY +// Universidad de Cantabria, SPAIN +// University of York, UK +// +// This file is part of FOSA (Frsh Operating System Abstraction) +// +// FOSA is free software; you can redistribute it and/or modify it +// under terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) any +// later version. FOSA is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. You should have received a +// copy of the GNU General Public License along with FOSA; see file +// COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, +// Cambridge, MA 02139, USA. +// +// As a special exception, including FOSA header files in a file, +// instantiating FOSA generics or templates, or linking other files +// with FOSA objects to produce an executable application, does not +// by itself cause the resulting executable application to be covered +// by the GNU General Public License. This exception does not +// however invalidate any other reasons why the executable file might be +// covered by the GNU Public License. +// ----------------------------------------------------------------------- +// fosa_time.c +//============================================== +// ******** ****** ******** ********** +// **///// /** ** **////// /** /** +// ** /** ** /** /** /** +// ******* /** ** /********* /********** +// **//// /** ** ////////** /**//////** +// ** /** ** /** /** /** +// ** /** ** ******** /** /** +// // /******/ //////// // // +// +// FOSA(Frescor Operating System Adaptation layer) +//================================================ + +#include "fosa_time.h" +#include "fosa_threads_and_signals.h" + +#define timespec_add(t1, t2, sum) \ + do { \ + (sum)->tv_sec = (t1).tv_sec + (t2).tv_sec; \ + (sum)->tv_nsec = (t1).tv_nsec + (t2).tv_nsec; \ + if ((sum)->tv_nsec >= 1000000000) { \ + (sum)->tv_sec++; \ + (sum)->tv_nsec -= 1000000000; \ + } \ + } while (0) + +#define timespec_smaller(t1, t2) \ + ( (t1).tv_sec < (t2).tv_sec || ((t1).tv_sec == (t2).tv_sec && \ + (t1).tv_nsec < (t2).tv_nsec) ) + +/** + * fosa_eat() + * + * Eat some time using system clock facilities + **/ +void inline fosa_eat(const struct timespec *cpu_time) +{ + int error; + fosa_thread_id_t self; + clockid_t clock_id; + struct timespec current_time, time_to_go; + + self = fosa_thread_self(); + if (self.linux_pid == self.linux_tid) + error = clock_getcpuclockid(self.linux_pid, &clock_id); + else + error = pthread_getcpuclockid(self.pthread_id, &clock_id); + if (error != 0) + return; + + if (clock_gettime(clock_id, ¤t_time) != 0) + return; + + timespec_add(current_time, *cpu_time, &time_to_go); + while (timespec_smaller(current_time, time_to_go)) + if (clock_gettime(clock_id, ¤t_time) != 0) + return; +} diff --git a/src_aquosa/frsh_fosa.c b/src_aquosa/frsh_fosa.c deleted file mode 100644 index f2a2d57..0000000 --- a/src_aquosa/frsh_fosa.c +++ /dev/null @@ -1,144 +0,0 @@ -// ----------------------------------------------------------------------- -// Copyright (C) 2006 - 2007 FRESCOR consortium partners: -// -// Universidad de Cantabria, SPAIN -// University of York, UK -// Scuola Superiore Sant'Anna, ITALY -// Kaiserslautern University, GERMANY -// Univ. Politecnica Valencia, SPAIN -// Czech Technical University in Prague, CZECH REPUBLIC -// ENEA SWEDEN -// Thales Communication S.A. FRANCE -// Visual Tools S.A. SPAIN -// Rapita Systems Ltd UK -// Evidence ITALY -// -// See http://www.frescor.org for a link to partners' websites -// -// FRESCOR project (FP6/2005/IST/5-034026) is funded -// in part by the European Union Sixth Framework Programme -// The European Union is not liable of any use that may be -// made of this code. -// -// This file is part of the FRSH implementation -// -// FRSH is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or (at your option) -// any later version. -// -// FRSH is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// distributed with FRSH; see file COPYING. If not, write to the -// Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -// -// ----------------------------------------------------------------------- -//frsh_fosa.c -//============================================== -// ******** ****** ******** ********** -// **///// /** ** **////// /** /** -// ** /** ** /** /** /** -// ******* /** ** /********* /********** -// **//// /** ** ////////** /**//////** -// ** /** ** /** /** /** -// ** /** ** ******** /** /** -// // /******/ //////// // // -// -// FOSA(Frescor Operating System Adaptation layer) -//================================================ - -#include "frsh_fosa.h" - -/************************* - * Thread attributes - *************************/ - -/** - * frsh_thread_attr_init() - * - * Initialize a thread attributes object - * - * This function initializes the object pointed to by attr to all - * the default values defined by FRSH - * - * @return 0 if successful; otherwise it returns \n - * FOSA_ENOMEM: insufficient memory exists to initialize the thread - * attributes object - **/ -int frsh_thread_attr_init(frsh_thread_attr_t *attr) -{ - int ret_value; - - ret_value=pthread_attr_init(attr); - /* if (ret_value==0) { - // set the default values - detachstate = detached thread (no join operation allowed) - CHK(pthread_attr_setdetachstate(attr,PTHREAD_CREATE_DETACHED)); - // inheritsched = explicit, so that we can explicitly set the attributes - CHK(pthread_attr_setinheritsched(attr,PTHREAD_EXPLICIT_SCHED)); - // schedpolicy = fixed priorities - CHK(pthread_attr_setschedpolicy(attr,SCHED_FIFO)); - // detachstate = detached thread (no join operation allowed) - CHK(pthread_attr_setdetachstate(attr,PTHREAD_CREATE_DETACHED)); - } */ - - return ret_value; -} - -/** - * frsh_thread_attr_destroy() - * - * Destroy a thread attributes object - * - * This function is used to destroy the thread attributes object, - * pointed to by attr, and deallocate any system resources allocated for it - * - * Returns 0 - */ -int frsh_thread_attr_destroy(frsh_thread_attr_t *attr) -{ - return pthread_attr_destroy(attr); -} - -/** - * frsh_thread_attr_set_stacksize() - * - * Set the thread minimum stack size in a thread attributes object - * - * This function sets the minimum stack size of the thread attributes - * object attr to the value given by stacksize, in bytes. This - * function has no runtime effect on the stack size, except when the - * attributes object is used to create a thread, when it will be - * created with the specified minimum stack size - * - * @return 0 if successful, or the following error code: - * FOSA_EINVAL: the specified stacksize value is not supported in - * this implementation - */ -int frsh_thread_attr_set_stacksize(frsh_thread_attr_t *attr, - size_t stacksize) -{ - return pthread_attr_setstacksize(attr,stacksize); -} - -/** - * frsh_thread_attr_get_stacksize() - * - * Get the thread minimum stack size from a thread attributes object - * - * This function sets the variable pointed to by stacksize to the - * minimum stack size stored in the thread attributes object attr. - * - * @return 0 - */ -int frsh_thread_attr_get_stacksize(const frsh_thread_attr_t *attr, - size_t *stacksize) -{ - return pthread_attr_getstacksize(attr,stacksize); -} -