ft_v1.0/0040755000374300000260000000000007477072670007506 5ustar fbft_v1.0/lib/0040755000374300000260000000000007477072670010254 5ustar fbft_v1.0/include/0040755000374300000260000000000007477072670011131 5ustar fbft_v1.0/src/0040755000374300000260000000000007477072670010275 5ustar fbft_v1.0/src/automaton.c0100644000374300000260000001271407477072670012452 0ustar fb#include "fthread_internal.h" /*********************************************************/ int _automaton_await (ft_thread_t self,ft_event_t event) { ft_scheduler_t sched = _get_thread_scheduler (self); _VERIFY_THREAD_CREATION_AND_LINK (self); _VERIFY_EVENT_CREATION_AND_SCHEDULER (event,sched); if (!_event_is_generated (event)) { _POST_EVENT (event,self); _set_thread_status (self,_WAIT); return _STAY; } return OK; } int _automaton_await_n (ft_thread_t self,ft_event_t event,int delay) { int current,deadline; ft_scheduler_t sched = _get_thread_scheduler (self); _VERIFY_THREAD_CREATION_AND_LINK (self); _VERIFY_EVENT_CREATION_AND_SCHEDULER (event,sched); deadline = _get_thread_deadline (self); current = _get_scheduler_instant (sched); if (deadline == -1) { _set_thread_deadline (self,(deadline = delay + current)); } if (deadline > current && !_event_is_generated (event)) { _POST_TIMER (self,sched,deadline); _POST_EVENT (event,self); _set_thread_status (self,_WAIT); return _STAY; } _set_thread_deadline (self,-1); if (deadline <= current) return ETIMEOUT; return OK; } /*********************************************************/ int _automaton_get_value (ft_thread_t self,ft_event_t event,int index,void **result) { ft_scheduler_t sched = _get_thread_scheduler (self); _VERIFY_THREAD_CREATION_AND_LINK (self); _VERIFY_EVENT_CREATION_AND_SCHEDULER (event,sched); if (_get_thread_deadline (self) == _get_scheduler_instant (sched)) { _set_thread_deadline (self,-1); result = NULL; return ENEXT; } if (_event_get_value (event,index,result)) return OK; if (_get_scheduler_eoi (sched) == 1) { _set_thread_deadline (self,_get_scheduler_instant (sched)+1); _set_thread_status (self,_DONE); return _STAY; } _set_thread_status (self,_BLOCKED); return _STAY; } /*********************************************************/ int _automaton_stay (ft_thread_t self,int delay) { int current,deadline; ft_scheduler_t sched = _get_thread_scheduler (self); _VERIFY_THREAD_CREATION_AND_LINK (self); deadline = _get_thread_deadline (self); current = _get_scheduler_instant (sched); if (deadline == -1) { _set_thread_deadline (self,(deadline = delay + current)); } if (deadline > current) { _POST_TIMER (self,sched,deadline); _set_thread_status (self,_WAIT); return _STAY; } _set_thread_deadline (self,-1); return OK; } /*********************************************************/ int _automaton_join (ft_thread_t self,ft_thread_t thread) { ft_scheduler_t sched = _get_thread_scheduler (self); _VERIFY_THREAD_CREATION_AND_LINK (self); _VERIFY_THREAD_CREATION (thread); if (_get_thread_status (thread) == _TERMINATED) { _set_scheduler_move (sched); return OK; } else if (_get_scheduler_eoi (sched)) { _set_thread_status (self,_DONE); return _STAY; } else { _set_thread_status (self,_BLOCKED); return _STAY; } } int _automaton_join_n (ft_thread_t self,ft_thread_t thread,int delay) { int current,deadline; ft_scheduler_t sched = _get_thread_scheduler (self); _VERIFY_THREAD_CREATION_AND_LINK (self); _VERIFY_THREAD_CREATION (thread); deadline = _get_thread_deadline (self); current = _get_scheduler_instant (sched); if (deadline == -1) { _set_thread_deadline (self,(deadline = delay + current)); } if (deadline <= current) { _set_thread_deadline (self,-1); return ETIMEOUT; } if (_get_thread_status (thread) == _TERMINATED) { _set_scheduler_move (sched); _set_thread_deadline (self,-1); return OK; } else if (_get_scheduler_eoi (sched)) { _set_thread_status (self,_DONE); return _STAY; } else { _set_thread_status (self,_BLOCKED); return _STAY; } } /*********************************************************/ int _automaton_select (ft_thread_t self,int length,ft_event_t *events,int *mask) { int i; ft_scheduler_t sched = _get_thread_scheduler (self); _VERIFY_THREAD_CREATION_AND_LINK (self); for (i=0;ievent = event; new->pure = pure; new->value = value; new->next = list; return new; } void _destroy_broadcast_list (broadcast_list_t list) { while(list != NULL) { broadcast_list_t next = list->next; free(list); list = next; } } void _generate_broadcast_list (broadcast_list_t list) { while(list != NULL){ if (list->pure) _event_generate (list->event); else _event_generate_value (list->event,list->value); list = list->next; } } ft_v1.0/src/environment.c0100644000374300000260000000577507477072670013020 0ustar fb#include "fthread_internal.h" #define ENVIRONMENT_CHUNK 100; /*****************************************************/ struct ft_environment_t { int move; int eoi; int instant; int size; ft_event_t *event_set; thread_list_t timer; }; /*****************************************************/ int _get_environment_eoi (ft_environment_t env) { return env->eoi; } void _set_environment_eoi (ft_environment_t env,int b) { env->eoi = b; } int _get_environment_move (ft_environment_t env) { return env->move; } void _set_environment_move (ft_environment_t env,int b) { env->move = b; } int _get_environment_instant (ft_environment_t env) { return env->instant; } int _timer_size (ft_environment_t env) { return _get_length_thread_list (env->timer); } /*****************************************************/ static void _event_set_malloc (ft_environment_t env) { env->size = ENVIRONMENT_CHUNK; env->event_set = malloc (env->size*sizeof (ft_event_t)); //fprintf(stderr,"allocation of %d events at %d!!!!\n",env->size,env->event_set); } static void _event_set_realloc (ft_environment_t env) { env->size += ENVIRONMENT_CHUNK; env->event_set = realloc (env->event_set,env->size*sizeof (ft_event_t)); //fprintf(stderr,"reallocation of %d events at %d!!!!\n",env->size,env->event_set); } /*****************************************************/ int _store_event_in_environment (ft_environment_t env,int index,ft_event_t event) { if (index == env->size) { _event_set_realloc (env); if (env->event_set == NULL) return EBADMEM; } (env->event_set)[index] = event; return OK; } void _add_to_timer (ft_environment_t env,ft_thread_t thread) { _add_thread_list (env->timer,thread); } /*****************************************************/ ft_environment_t _environment_create (void) { ft_environment_t new = malloc (sizeof (struct ft_environment_t)); if (new == NULL) return NULL; new->move = 0; new->eoi = 0; new->instant = 0; _event_set_malloc (new); if (NULL == new->event_set) return NULL; new->timer = _create_thread_list (); if (new->timer == NULL) return NULL; return new; } /*****************************************************/ static int _deadline_reached (ft_thread_t thread) { ft_scheduler_t sched = _get_thread_scheduler (thread); ft_environment_t env = _get_scheduler_environment (sched); int deadline = _get_thread_deadline (thread); if (deadline > env->instant) return 0; // keep it if (_get_thread_status (thread) == _WAIT) _set_thread_status (thread,_READY); return 1; // remove it } static void _awake_deadline_reached (ft_environment_t env) { _apply_thread_list (env->timer,_deadline_reached); } /*****************************************************/ void _new_instant (ft_environment_t env) { env->instant++; env->move = 0; env->eoi = 0; _awake_deadline_reached (env); // awake threads reaching the deadline } ft_v1.0/src/event.c0100644000374300000260000001027607477072670011565 0ustar fb#include "fthread_internal.h" #define VALUES_CHUNK 10 /*******************************************/ struct ft_event_t { int num; int instant; ft_scheduler_t scheduler; void **values; int value_max; int value_count; int well_created; // == FT_MAGIC if creation is OK thread_list_t waiting; }; /*******************************************/ int _event_well_created (ft_event_t event) { return event->well_created == FT_MAGIC; } ft_scheduler_t _get_event_scheduler (ft_event_t event) { return event->scheduler; } int _event_get_value (ft_event_t event,int index,void **result) { if (_event_is_generated(event) && event->value_count > index) { (*result) = (event->values)[index]; return 1; } return 0; } /*******************************************/ // thread-safe generation of a new index number for events static pthread_mutex_t _event_lock; static int _event_num = 0; static int new_event_num () { int res; if (_event_num == 0) pthread_mutex_init (&_event_lock,NULL); pthread_mutex_lock (&_event_lock); res = _event_num++; pthread_mutex_unlock (&_event_lock); return res; } /********************************************/ // allocation of the array of values associated to an event static void* values_malloc (ft_event_t evt) { evt->value_max = VALUES_CHUNK; evt->values = malloc (1+evt->value_max*sizeof (void*)); return evt->values; } static void* values_realloc (ft_event_t evt) { evt->value_max += VALUES_CHUNK; evt->values = realloc (evt->values,1+evt->value_max*sizeof (void*)); return evt->values; } /********************************************/ ft_event_t ft_event_create (ft_scheduler_t sched) { ft_event_t new_event = malloc (sizeof (struct ft_event_t)); if (new_event == NULL || sched == NULL || !_scheduler_well_created (sched)) return NULL; new_event->num = new_event_num (); new_event->instant = -1; new_event->scheduler = sched; new_event->value_count = 0; if (values_malloc (new_event) == NULL) return NULL; if (_store_event (sched,new_event->num,new_event) == EBADMEM) return NULL; if (NULL == (new_event->waiting = _create_thread_list ())) return NULL; new_event->well_created = FT_MAGIC; //fprintf(stderr,"create event %d \n",new_event->num); return new_event; } /********************************************/ static int _awake_thread (ft_thread_t thread) { if (_get_thread_status (thread) == _WAIT) { //fprintf (stderr, "awake thread %ld\n",thread); _set_thread_status (thread,_BLOCKED); } return 1; } static void _awake_waiting_threads (ft_event_t event) { _apply_thread_list (event->waiting,_awake_thread); } void _event_store_thread (ft_event_t event,ft_thread_t thread) { //fprintf (stderr, "store waiting thread %ld\n",thread); _add_thread_list (event->waiting,thread); } /********************************************/ int _event_is_generated (ft_event_t event) { return event->instant == _get_scheduler_instant (event->scheduler); } // sets the mask and returns 1 if there is a generated event, 0 otherwise int _fill_mask (int length,ft_event_t *events,int *mask) { int res=0,i,pres; for (i=0;iinstant = _get_scheduler_instant (event->scheduler); _set_scheduler_move (event->scheduler); event->value_count = 0; // reset event values _awake_waiting_threads (event); // awake threads waiting for the event } } int _event_generate_value (ft_event_t event,void *val) { _event_generate (event); // may be somebody waits for using the new value... _set_scheduler_move (event->scheduler); if (event->value_count == event->value_max) { if (values_realloc (event) == NULL) return EBADMEM; } event->values[event->value_count++] = val; return OK; } ft_v1.0/src/instruction.c0100644000374300000260000001556007477072670013026 0ustar fb#include "fthread_internal.h" /************************************************/ int ft_thread_cooperate () { ft_thread_t self = ft_thread_self (); _VERIFY_THREAD_CREATION_AND_LINK (self); _release(self,_DONE); return OK; } int ft_thread_cooperate_n (int delay) { int deadline; ft_thread_t self = ft_thread_self (); ft_scheduler_t sched = ft_thread_scheduler (); _VERIFY_THREAD_CREATION_AND_LINK (self); deadline = delay + _get_scheduler_instant (sched); while (1) { if (deadline <= _get_scheduler_instant (sched)) return OK; _POST_TIMER (self,sched,deadline); _release (self,_WAIT); } } /************************************************/ int ft_thread_await (ft_event_t event) { ft_thread_t self = ft_thread_self (); ft_scheduler_t sched = ft_thread_scheduler (); _VERIFY_THREAD_CREATION_AND_LINK (self); _VERIFY_EVENT_CREATION_AND_SCHEDULER (event,sched); while (1) { if (_event_is_generated(event)) return OK; // present else if (_get_scheduler_eoi (sched)) _release (self,_DONE); // absent else { _POST_EVENT (event,self); _release (self,_WAIT); } } } int ft_thread_await_n (ft_event_t event,int delay) { int deadline; ft_thread_t self = ft_thread_self (); ft_scheduler_t sched = ft_thread_scheduler (); _VERIFY_THREAD_CREATION_AND_LINK (self); _VERIFY_EVENT_CREATION_AND_SCHEDULER (event,sched); deadline = delay + _get_scheduler_instant (sched); while(1) { _CONTROL_TIMEOUT (deadline,sched); if (_event_is_generated (event)) return OK; else if (_get_scheduler_eoi (sched)) _release (self,_DONE); else { _POST_TIMER (self,sched,deadline); _POST_EVENT (event,self); _release (self,_WAIT); } } } /************************************************/ int ft_thread_join (ft_thread_t thread) { ft_thread_t self = ft_thread_self (); ft_scheduler_t sched = ft_thread_scheduler (); _VERIFY_THREAD_CREATION_AND_LINK (self); _VERIFY_THREAD_CREATION (thread); while (1) { if (_get_thread_status (thread) == _TERMINATED) { /* if termination comes from an asynchronous thread and somebody also waits for termination, one must be sure that it sees termination at the same instant. */ _set_scheduler_move (sched); return OK; } else if (_get_scheduler_eoi (sched)) _release (self,_DONE); else _release (self,_BLOCKED); } } int ft_thread_join_n (ft_thread_t thread,int delay) { int deadline; ft_thread_t self = ft_thread_self (); ft_scheduler_t sched = ft_thread_scheduler (); _VERIFY_THREAD_CREATION_AND_LINK (self); _VERIFY_THREAD_CREATION (thread); deadline = delay + _get_scheduler_instant (sched); while(1) { _CONTROL_TIMEOUT (deadline,sched); if (_get_thread_status (thread) == _TERMINATED) { _set_scheduler_move (sched); return OK; } else if (_get_scheduler_eoi (sched) == 1) { delay--; _release (self,_DONE); } else _release (self,_BLOCKED); } } /************************************************/ int ft_thread_get_value (ft_event_t event,int index,void **result) { ft_thread_t self = ft_thread_self (); ft_scheduler_t sched = ft_thread_scheduler (); _VERIFY_THREAD_CREATION_AND_LINK (self); _VERIFY_EVENT_CREATION_AND_SCHEDULER (event,sched); while(1) { if (_event_get_value (event,index,result)) return OK; if (_get_scheduler_eoi (sched) == 1) break; _release (self,_BLOCKED); } _release (self,_DONE); result = NULL; return ENEXT; } /************************************************/ int ft_thread_generate (ft_event_t event) { ft_thread_t self = ft_thread_self (); ft_scheduler_t sched = ft_thread_scheduler (); _VERIFY_THREAD_CREATION_AND_LINK (self); _VERIFY_EVENT_CREATION_AND_SCHEDULER (event,sched); _event_generate (event); return OK; } int ft_thread_generate_value (ft_event_t event,void* val) { ft_thread_t self = ft_thread_self (); ft_scheduler_t sched = ft_thread_scheduler (); _VERIFY_THREAD_CREATION_AND_LINK (self); _VERIFY_EVENT_CREATION_AND_SCHEDULER (event,sched); return _event_generate_value (event,val); } /************************************************/ int ft_thread_mutex_lock (pthread_mutex_t *mutex) { ft_thread_t self = ft_thread_self (); ft_scheduler_t sched = ft_thread_scheduler (); if (self == NULL || sched == NULL) return pthread_mutex_lock(mutex); _add_lock (self,mutex); while(1){ if (_get_scheduler_eoi (sched) == 1) { _release (self,_DONE); }else if (pthread_mutex_trylock (mutex) == OK) { return OK; }else{ _release (self,_BLOCKED); } } } int ft_thread_mutex_unlock (pthread_mutex_t *mutex) { ft_thread_t self = ft_thread_self (); int res = pthread_mutex_unlock (mutex); if (self != NULL) { ft_scheduler_t sched = _get_thread_scheduler (self); if (sched != NULL){ _set_scheduler_move (sched); _remove_lock (self,mutex); } } return res; } /***********************************************/ int ft_thread_select (int length,ft_event_t *events,int *mask) { int i; ft_thread_t self = ft_thread_self (); ft_scheduler_t sched = ft_thread_scheduler (); _VERIFY_THREAD_CREATION_AND_LINK (self); for (i=0;ilock = lock; new->next = list; return new; } lock_list_t _remove_from_lock_list (pthread_mutex_t *lock,lock_list_t list) { lock_list_t initial = list, previous; if (list == NULL) return NULL; if (list->lock == lock) return list->next; previous = list; while(NULL != (list = list->next)){ if (list->lock == lock) { previous->next = list->next; free (list); return initial; } previous = list; } return initial; } void _unlock_all (lock_list_t list) { while(list != NULL){ lock_list_t next = list->next; pthread_mutex_unlock (list->lock); free (list); list = next; } } ft_v1.0/src/scheduler.c0100644000374300000260000002736607477072670012432 0ustar fb#include "fthread_internal.h" #include /******************************************/ struct ft_scheduler_t { ft_thread_t self; thread_list_t thread_table; thread_list_t to_run; thread_list_t to_stop; thread_list_t to_suspend; thread_list_t to_resume; thread_list_t to_unlink; broadcast_list_t to_broadcast; pthread_mutex_t sleeping; pthread_cond_t awake; ft_environment_t environment; int well_created; // == FT_MAGIC if creation is OK }; /******************************************/ int _scheduler_well_created (ft_scheduler_t sched) { return sched->well_created == FT_MAGIC; } ft_environment_t _get_scheduler_environment (ft_scheduler_t sched) { return sched->environment; } ft_thread_t _get_scheduler_self (ft_scheduler_t sched) { return sched->self; } int _get_scheduler_eoi (ft_scheduler_t sched) { return _get_environment_eoi (sched->environment); } void _set_scheduler_move (ft_scheduler_t sched) { _set_environment_move (sched->environment,1); } int _get_scheduler_instant (ft_scheduler_t sched) { return _get_environment_instant (sched->environment); } /******************************************/ int _store_event (ft_scheduler_t sched,int index,ft_event_t event) { return _store_event_in_environment (sched->environment,index,event); } void _store_in_timer (ft_scheduler_t sched,ft_thread_t thread) { _add_to_timer (sched->environment,thread); } /******************************************/ static int _can_run (ft_thread_t thread) { int status = _get_thread_status (thread); return status != _SUSPENDED && status != _TERMINATED && status != _WAIT; } static int _is_fireable (ft_thread_t thread) { int status = _get_thread_status (thread); return status == _READY || status == _BLOCKED; } /******************************************************/ #define FOR_ALL_THREADS \ thread_list_t table = sched->thread_table;\ thread_cell_t cell = _get_first_thread_list (table);\ while (cell != NULL){\ ft_thread_t thread = _get_content_thread_cell (cell); #define END_FOR_ALL \ cell = _get_next_thread_cell (cell);\ } /******************************************************/ static int _all_done (ft_scheduler_t sched) { FOR_ALL_THREADS int status = _get_thread_status (thread); if (_can_run (thread) && status != _DONE) return 0; END_FOR_ALL return 1; } static int _all_blocked_or_done (ft_scheduler_t sched) { FOR_ALL_THREADS int status = _get_thread_status (thread); if (_can_run (thread) && status != _DONE && status != _BLOCKED) return 0; END_FOR_ALL return 1; } /******************************************************/ static void _fire_all_threads (ft_scheduler_t sched) { FOR_ALL_THREADS if (_is_fireable (thread)){ if (!_is_automaton (thread)) { //fprintf(stderr,"scheduler fires thread %ld\n",thread); _transmit_token (sched->self,thread); //fprintf(stderr,"scheduler returns from thread %ld\n",thread); } else { //fprintf(stderr,"scheduler fires automaton %ld\n",(long)thread); _run_as_automaton (thread); } } END_FOR_ALL } /******************************************************/ static void _next_step (ft_scheduler_t sched) { FOR_ALL_THREADS int status = _get_thread_status (thread); if (status == _BLOCKED) _set_thread_status (thread,_READY); END_FOR_ALL } static int _micro_step (ft_scheduler_t sched) { _set_environment_move (sched->environment,0); _fire_all_threads (sched); if (_all_done (sched)) return 1; if (_all_blocked_or_done (sched)){ if (_get_environment_move (sched->environment) == 0) _set_environment_eoi (sched->environment,1); _next_step (sched); } return 0; } /******************************************************/ static int _somebody_must_be_continued (ft_scheduler_t sched) { FOR_ALL_THREADS int status = _get_thread_status (thread); if (status == _READY) return 1; END_FOR_ALL return 0; } static int _something_to_do (ft_scheduler_t sched) { return _timer_size (sched->environment) > 0 || _somebody_must_be_continued (sched) || _get_length_thread_list (sched->to_run) > 0 || _get_length_thread_list (sched->to_resume) > 0 || _get_length_thread_list (sched->to_unlink) > 0 || sched->to_broadcast != NULL; } /******************************************************/ static void _sleep_if_nothing_to_do (ft_scheduler_t sched) { _PTH_LOCK(sched->sleeping); while (!_something_to_do (sched)){ //fprintf(stderr,"scheduler %ld falls asleep..\n",(long)sched->self); _PTH_WAIT(sched->awake,sched->sleeping); //fprintf(stderr,"scheduler %ld awakes..\n",(long)sched->self); } _PTH_UNLOCK(sched->sleeping); } static void _awake (ft_scheduler_t sched) { _PTH_LOCK(sched->sleeping); //fprintf (stderr,"awake scheduler thread %ld\n",(long)sched->self); _PTH_NOTIFY(sched->awake,sched->sleeping); _PTH_UNLOCK(sched->sleeping); } /******************************************************/ static void _incorporate_orders (ft_scheduler_t sched); static void _init_instant (ft_scheduler_t sched) { _sleep_if_nothing_to_do (sched); _new_instant (sched->environment); _incorporate_orders (sched); //_trace_instant (sched); } static void _finish_instant (ft_scheduler_t sched) { FOR_ALL_THREADS int status = _get_thread_status (thread); if (status == _DONE) _set_thread_status (thread,_READY); END_FOR_ALL } static void _one_instant (ft_scheduler_t sched) { _init_instant (sched); while (!_micro_step (sched)){/* nothing */} _finish_instant (sched); } /*****************************************************/ static void* _scheduler_behavior (void *arg) { ft_scheduler_t sched = (ft_scheduler_t)arg; while (1) { _one_instant (sched); sched_yield (); } return NULL; } /*****************************************************/ ft_scheduler_t ft_scheduler_create (void) { pthread_mutex_t sleeping; pthread_cond_t awake; ft_scheduler_t sched = malloc (sizeof (struct ft_scheduler_t)); if (sched == NULL) return NULL; sched->self = _make_thread (); if (NULL == (sched->thread_table = _create_thread_list ())) return NULL; if (NULL == (sched->to_run = _create_thread_list ())) return NULL; if (NULL == (sched->to_stop = _create_thread_list ())) return NULL; if (NULL == (sched->to_suspend = _create_thread_list ())) return NULL; if (NULL == (sched->to_resume = _create_thread_list ())) return NULL; if (NULL == (sched->to_unlink = _create_thread_list ())) return NULL; sched->to_broadcast = NULL; pthread_mutex_init (&sleeping,NULL); pthread_cond_init (&awake,NULL); sched->sleeping = sleeping; sched->awake = awake; sched->environment = _environment_create (); if (sched->environment != NULL) sched->well_created = FT_MAGIC; return sched; } int ft_scheduler_start (ft_scheduler_t sched) { int res; pthread_t pth; _VERIFY_SCHEDULER_CREATION(sched); pth = ft_pthread (sched->self); res = pthread_create (&pth,NULL,_scheduler_behavior,sched); //if (res == 0) fprintf (stderr,"scheduler %d started\n",(int)sched->self); return res; } /*****************************************************/ static void _trace_instant (ft_scheduler_t sched) { fprintf (stderr,"\n>>> instant %d ",_get_scheduler_instant(sched)); _trace_thread_list (sched->thread_table); fprintf (stderr,": "); } /*******************************************************/ #define ORDER(set)\ {\ int res;\ ft_scheduler_t sched = _get_thread_scheduler (thread);\ ft_thread_t s = sched->self;\ _lock_thread (s);\ res = _add_thread_list (sched->set,thread);\ _unlock_thread (s);\ _awake (sched);\ return res;\ } int _register_as_runnable (ft_thread_t thread) { _VERIFY_THREAD_CREATION(thread); ORDER(to_run); } int ft_scheduler_stop (ft_thread_t thread) { _VERIFY_THREAD_CREATION_AND_LINK (thread); ORDER(to_stop); } int ft_scheduler_suspend (ft_thread_t thread) { _VERIFY_THREAD_CREATION_AND_LINK (thread); ORDER(to_suspend); } int ft_scheduler_resume (ft_thread_t thread) { _VERIFY_THREAD_CREATION_AND_LINK (thread); ORDER(to_resume); } int _register_unlink_order (ft_thread_t thread) { _VERIFY_THREAD_CREATION_AND_LINK (thread); ORDER(to_unlink); } /*******************************************************/ static void _broadcast_to_generate (ft_scheduler_t sched) { if (sched->to_broadcast != NULL){ _generate_broadcast_list (sched->to_broadcast); _destroy_broadcast_list(sched->to_broadcast); sched->to_broadcast = NULL; } } /*******************************************************/ static int _broadcast (ft_event_t event,int pure,void *val){ int res; ft_scheduler_t sched; _VERIFY_EVENT_CREATION (event); sched = _get_event_scheduler (event); _lock_thread (sched->self); sched->to_broadcast = _add_to_broadcast_list (event,pure,val,sched->to_broadcast); res = (sched->to_broadcast == NULL) ? EBADMEM : OK; _unlock_thread (sched->self); _awake (sched); // awake scheduler which is possibly sleeping return res; } int ft_scheduler_broadcast (ft_event_t event){ return _broadcast(event,1,NULL); } int ft_scheduler_broadcast_value (ft_event_t event,void *val){ return _broadcast(event,0,val); } /******************************************/ #define INIT_PROCESSING(set)\ thread_list_t table = sched->set;\ thread_cell_t cell = _get_first_thread_list (table);\ if (_get_length_thread_list (table) != 0) {\ while(cell != NULL){\ ft_thread_t thread = _get_content_thread_cell (cell); #define END_PROCESSING(set)\ cell = _get_next_thread_cell (cell);\ }\ _reset_thread_list (table);\ }\ /******************************************/ static void _resume (ft_thread_t thread) { int status = _get_thread_status (thread); if (status == _SUSPENDED || status == _WAIT) { _set_thread_status (thread,_READY); } } static void _run_processing (ft_scheduler_t sched) { INIT_PROCESSING (to_run) _set_thread_status (thread,_READY); _set_thread_scheduler (thread,sched); _add_thread_list (sched->thread_table,thread); END_PROCESSING (to_run) } static void _stop_processing (ft_scheduler_t sched) { INIT_PROCESSING (to_stop) _stop_thread (thread); _resume (thread); // resume END_PROCESSING (to_stop) } static void _suspend_processing (ft_scheduler_t sched) { INIT_PROCESSING (to_suspend) _set_thread_status (thread,_SUSPENDED); // suspend END_PROCESSING (to_suspend) } static void _resume_processing (ft_scheduler_t sched) { INIT_PROCESSING (to_resume) _resume (thread); // resume END_PROCESSING (to_resume) } static void _unlink_processing (ft_scheduler_t sched) { INIT_PROCESSING (to_unlink) _set_thread_scheduler (thread,NULL); // unlink END_PROCESSING (to_unlink) } /********************************************/ // perform unlinking and remove terminated and unlinked threads static int _purge (ft_thread_t thread) { if (_get_thread_scheduler (thread) == NULL) { _give_token_to (thread); // real unlinking return 1; // remove } if (_get_thread_status (thread) == _TERMINATED) { return 1; // remove } return 0; // keep it } static void _incorporate_orders (ft_scheduler_t sched) { _lock_thread (sched->self); _run_processing (sched); _broadcast_to_generate (sched); _stop_processing (sched); _unlink_processing (sched); _apply_thread_list (sched->thread_table,_purge); _resume_processing (sched); _suspend_processing (sched); // suspend prefered to resume _unlock_thread (sched->self); } ft_v1.0/src/test.c0100644000374300000260000000117507477072670011421 0ustar fb#include "fthread.h" #include /*********************************/ void traceInstants (void *args) { int i = 0; for (i=0;i<1000000;i++) { //fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i); ft_thread_cooperate (); } fprintf (stdout, "exit!\n"); exit (0); } int main () { int i; ft_scheduler_t sched = ft_scheduler_create (); for (i=0;i<1000;i++){ ft_event_t event = ft_event_create (sched); ft_scheduler_broadcast (event); } ft_thread_create (sched,traceInstants,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result end result */ ft_v1.0/src/thread.c0100644000374300000260000002253107477072670011710 0ustar fb#include "fthread_internal.h" /******************************************/ struct ft_thread_t { pthread_t pthread; // underlying pthread int well_created; // equals FT_MAGIC if creation is OK pthread_mutex_t lock; pthread_cond_t token; int has_token; ft_executable_t cleanup; // cleanup function, run when stopped ft_executable_t run; // the thread function void *args; // parameters for run and cleanup ft_scheduler_t scheduler; // scheduler of the thread int status; // status of the thread int stopped; // set when stopped lock_list_t locks; // list of locks owned by the thread int deadline; // limit time when waiting int is_automaton; // is it an automaton ? ft_automaton_t automaton; // automaton function int state; // automaton state void *local; // local data int return_code; // return code for instructions run by the automaton }; /******************************************/ ft_scheduler_t _get_thread_scheduler (ft_thread_t thread) { return thread->scheduler; } void _set_thread_scheduler (ft_thread_t thread,ft_scheduler_t sched) { thread->scheduler = sched; } int _get_thread_status (ft_thread_t thread) { return thread->status; } void _set_thread_status (ft_thread_t thread,int status) { thread->status = status; } int _get_thread_deadline (ft_thread_t thread) { return thread->deadline; } void _set_thread_deadline (ft_thread_t thread,int deadline) { thread->deadline = deadline; } int _is_automaton (ft_thread_t thread) { return thread->is_automaton; } int _get_thread_state (ft_thread_t thread) { return thread->state; } void _set_thread_state (ft_thread_t thread,int state) { thread->state = state; } void* _get_thread_args (ft_thread_t thread) { return thread->args; } void* _get_thread_local (ft_thread_t thread) { return thread->local; } void _set_thread_local (ft_thread_t thread,void *data) { thread->local = data; } int _get_thread_return_code (ft_thread_t thread) { return thread->return_code; } void _set_thread_return_code (ft_thread_t thread,int code) { thread->return_code = code; } /*****************************************************/ void _add_lock (ft_thread_t thread,pthread_mutex_t *mutex) { thread->locks = _add_to_lock_list (mutex,thread->locks); } void _remove_lock (ft_thread_t thread,pthread_mutex_t *mutex) { thread->locks = _remove_from_lock_list (mutex,thread->locks); } /*****************************************************/ void _stop_thread (ft_thread_t thread) { thread->stopped = 1; } /*****************************************************/ int _thread_well_created (ft_thread_t thread) { return thread->well_created == FT_MAGIC; } /************************************************/ /************************************************/ void _lock_thread (ft_thread_t thread) { _PTH_LOCK(thread->lock); } void _unlock_thread (ft_thread_t thread) { _PTH_UNLOCK(thread->lock); } void _wait_thread (ft_thread_t thread) { _PTH_WAIT(thread->token,thread->lock); } void _notify_thread (ft_thread_t thread) { _PTH_NOTIFY(thread->token,thread->lock); } static void _wait_for_token (ft_thread_t thread){ _lock_thread (thread); while (thread->has_token == 0) _wait_thread (thread); thread->has_token = 0; _unlock_thread (thread); } void _give_token_to (ft_thread_t thread){ _lock_thread (thread); thread->has_token = 1; _notify_thread (thread); _unlock_thread (thread); } void _transmit_token (ft_thread_t source,ft_thread_t target){ _give_token_to (target); _wait_for_token (source); } /*****************************************************/ static pthread_once_t _once_self_key = PTHREAD_ONCE_INIT; static pthread_key_t _self_key; static void _init_self_key (void) { pthread_key_create (&_self_key,NULL); } /*****************************************************/ ft_thread_t ft_thread_self (void) // no sense with automata { return pthread_getspecific (_self_key); } ft_scheduler_t ft_thread_scheduler (void) // no sense with automata { ft_thread_t res = ft_thread_self (); if (res == NULL) return NULL; return res->scheduler; } /************************************************/ /************************************************/ void _terminate (ft_thread_t thread) { thread->status = _TERMINATED; _unlock_all (thread->locks); if (thread->is_automaton) return; if (thread->scheduler != NULL) { _give_token_to (_get_scheduler_self (thread->scheduler)); } pthread_exit (0); //never pass through } /*****************************************************/ /*atomically: register in the scheduler, notify the creation function, and wait the token from the scheduler */ int _start_phase (ft_thread_t thread) { int res; _lock_thread (thread); res = _register_as_runnable (thread); _notify_thread (thread); if (res == OK){ while (thread->has_token == 0) _wait_thread (thread); thread->has_token = 0; } _unlock_thread (thread); return res; } static void* _standard_behavior (void *param) { /*the current thread is the parameter */ ft_thread_t me = param; pthread_setspecific (_self_key,me); if (_start_phase (me) != OK) return NULL; // cannot register => nothing done me->run (me->args); _terminate (me); // normal termination return NULL; } /*****************************************************/ ft_thread_t _make_thread (void) { pthread_mutex_t lock; pthread_cond_t token; ft_thread_t thread = malloc (sizeof (struct ft_thread_t)); if (thread == NULL) return NULL; pthread_mutex_init (&lock,NULL); pthread_cond_init (&token,NULL); thread->pthread = 0; thread->lock = lock; thread->token = token; thread->cleanup = NULL; thread->run = NULL; thread->args = NULL; thread->scheduler = NULL; thread->status = _READY; thread->has_token = 0; thread->stopped = 0; thread->locks = NULL; thread->deadline = -1; thread->is_automaton = 0; thread->automaton = NULL; thread->state = 0; thread->local = NULL; thread->return_code = 0; return thread; } ft_thread_t ft_thread_create (ft_scheduler_t sched, ft_executable_t runnable, ft_executable_t cleanup, void *args) { int res; ft_thread_t thread; if (sched == NULL || !_scheduler_well_created (sched)) return NULL; pthread_once (&_once_self_key,_init_self_key); if (NULL == (thread = _make_thread ())) return NULL; thread->run = runnable; thread->cleanup = cleanup; thread->args = args; thread->scheduler = sched; // scheduler is set // create the pthread and wait until it is running _lock_thread (thread); res = pthread_create (&thread->pthread,NULL,_standard_behavior,thread); if (res == OK) thread->well_created = FT_MAGIC; _wait_thread (thread); _unlock_thread (thread); return thread; } /************************************************/ pthread_t ft_pthread (ft_thread_t thread) { if (thread == NULL) return 0; return thread->pthread; } /*****************************************************/ void _release (ft_thread_t thread,int status) { ft_scheduler_t sched = _get_thread_scheduler (thread); _set_thread_status (thread,status); _transmit_token (thread,_get_scheduler_self(sched)); if (thread->stopped) { if (thread->cleanup != NULL) thread->cleanup (thread->args); _terminate (thread); } } /************************************************/ void _trace_thread (ft_thread_t thread) { if (thread->status == _WAIT) fprintf (stderr, "%ld* ",(long)thread); else fprintf (stderr, "%ld ",(long)thread); } /************************************************/ void ft_exit (void) { ft_thread_t me = ft_thread_self (); if (me != NULL) { _terminate (me); } else pthread_exit (NULL); } /*****************************************************/ /*****************************************************/ ft_thread_t ft_automaton_create (ft_scheduler_t sched, ft_automaton_t automaton, ft_executable_t cleanup, void *args) { ft_thread_t thread; if (sched == NULL || !_scheduler_well_created (sched)) return NULL; pthread_once (&_once_self_key,_init_self_key); if (NULL == (thread = _make_thread ())) return NULL; thread->cleanup = cleanup; thread->args = args; thread->scheduler = sched; // scheduler is set thread->is_automaton = 1; thread->automaton = automaton; thread->well_created = FT_MAGIC; // before registrating... if (OK != _register_as_runnable (thread)) return NULL; return thread; } void _run_as_automaton (ft_thread_t thread) { if (thread->stopped) { if (thread->cleanup != NULL) thread->cleanup (thread->args); _terminate (thread); } else { pthread_setspecific (_self_key,thread); thread->automaton (thread); } } ft_v1.0/src/threadlist.c0100644000374300000260000000633207477072670012605 0ustar fb#include "fthread_internal.h" struct thread_cell_t { ft_thread_t content; struct thread_cell_t *next; }; struct thread_list_t { int length; thread_cell_t first; thread_cell_t last; }; /***********************************************************/ int _get_length_thread_list (thread_list_t list) { return list->length; } thread_cell_t _get_first_thread_list (thread_list_t list) { return list->first; } ft_thread_t _get_content_thread_cell (thread_cell_t cell) { return cell->content; } thread_cell_t _get_next_thread_cell (thread_cell_t cell) { return cell->next; } /***********************************************************/ // creation thread_list_t _create_thread_list (void) { thread_list_t res = malloc (sizeof (struct thread_list_t)); res->length = 0; res->first = NULL; res->last = NULL; return res; } // add a new thread as last element int _append_thread_list (thread_list_t list,ft_thread_t thread) { thread_cell_t new = malloc (sizeof (struct thread_cell_t)); if (NULL == new) return EBADMEM; new->content = thread; new->next = NULL; if (0 == list->length){ list->first = list->last = new; }else{ list->last->next = new; list->last = new; } list->length++; return OK; } // reset the list void _reset_thread_list (thread_list_t list) { if (list->length != 0) { thread_cell_t cell = list->first; while (cell != NULL) { thread_cell_t next = cell->next; free (cell); cell = next; } } list->length = 0; list->first = NULL; list->last = NULL; } // is a thread contained in the list ? int _contains_thread_list (thread_list_t list,ft_thread_t thread) { if (list->length != 0) { thread_cell_t cell = list->first; while (cell != NULL) { thread_cell_t next = cell->next; if (cell->content == thread) return 1; cell = next; } } return 0; } // add a new thread if not already present in the list int _add_thread_list (thread_list_t list,ft_thread_t thread) { if (_contains_thread_list (list,thread)) return OK; return _append_thread_list (list,thread); } // apply a function f to all threads in the list. // f(thread) returns 1 = remove the thread, 0 keep it void _apply_thread_list (thread_list_t list,thread_list_map_t f) { thread_cell_t cell, previous = NULL; if (list->length == 0) return; cell = list->first; while (cell != NULL) { if (f (cell->content)) { // remove cell list->length--; if (previous == NULL) { // cell first item list->first = cell->next; free (cell); cell = list->first; } else if (cell == list->last) { // cell last item previous->next = NULL; list->last = previous; free (cell); return; } else { previous->next = cell->next; free (cell); cell = previous->next; } } else { // keep cell previous = cell; cell = cell->next; } } } // trace function void _trace_thread_list (thread_list_t list) { fprintf (stderr, "[ "); if (list->length != 0) { thread_cell_t cell = list->first; while (cell != NULL) { thread_cell_t next = cell->next; _trace_thread (cell->content); cell = next; } } fprintf (stderr, "]\n"); } ft_v1.0/src/automaton.h0100644000374300000260000001466407477072670012465 0ustar fb/* Fair threads automata API for C */ /* Copyright (C) 2002 Frederic Boussinot (Frederic.Boussinot@inria.fr) */ /* */ /* This program is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU Library General Public License */ /* as published by the Free Software Foundation; either version 2 */ /* of the License, or (at your option) any later version. */ /* */ /* This program 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 Library General Public License for more details. */ #ifndef _AUTOMATON_H #define _AUTOMATON_H /****************************************************/ typedef void (*automaton_t)(ft_thread_t); ft_thread_t ft_automaton_create (ft_scheduler_t,automaton_t,executable_t,void *args); #define DEFINE_AUTOMATON(name) _DEFINE_AUTOMATON(name) #define BEGIN_AUTOMATON _BEGIN_AUTOMATON #define STATE(n) _STATE(n) #define END_AUTOMATON _END_AUTOMATON #define GOTO_NEXT _GOTO_NEXT #define GOTO(n) _GOTO(n) #define IMMEDIATE(n) _IMMEDIATE(n) #define SELF _SELF #define SET_LOCAL(data) _SET_LOCAL(data) #define LOCAL _LOCAL #define ARGS _ARGS #define RETURN_CODE _RETURN_CODE #define AWAIT(event) _AWAIT(event) #define AWAIT_N(event,delay) _AWAIT_N(event,delay) #define GENERATE(event) _GENERATE(event) #define GENERATE_VALUE(event,val) _GENERATE_VALUE(event,val) #define GET_VALUE(event,n,result) _GET_VALUE(event,n,result) #define STAY(delay) _STAY_INST(delay) #define JOIN(thread) _JOIN(thread) #define JOIN_N(thread,delay) _JOIN_N(thread,delay) /********************************************** internal definitions: should not be used ***********************************************/ #define _DEFINE_AUTOMATON(name)\ void name (ft_thread_t _self)\ #define _BEGIN_AUTOMATON\ while (1) {\ int state = _get_thread_state (_self);\ switch (state)\ { #define _STATE(n)\ case n: _SET_STATE(n); #define _END_AUTOMATON\ default: _SET_STATE(-1); \ _terminate (_self);\ return;\ }\ } #define _GOTO_NEXT {_SET_STATE(state+1); _SET_STATUS(_DONE);} #define _GOTO(n) {_SET_STATE(n); _SET_STATUS(_DONE);} #define _IMMEDIATE(n) {_SET_STATE(n); break;} /****************************************************/ #define _SELF _self #define _SET_LOCAL(data) _set_thread_local (_self,(void*)data) #define _LOCAL _get_thread_local (_self) #define _ARGS _get_thread_args (_self) #define _RETURN_CODE _get_thread_return_code (_self) /****************************************************/ /****************************************************/ #define _READY 0 // ready to run #define _BLOCKED 2 // waiting to be reexecuted during the same instant #define _DONE 3 // nothing to be done for current instant #define _TERMINATED 4 // nothing to be done in the future #define _SUSPENDED 5 // suspended, waiting to be resumed #define _WAIT 6 // waiting for an event to be generated #define _STAY 7 // automaton stays in the same state /****************************************************/ int _automaton_stay (ft_thread_t self,int delay); int _automaton_await (ft_thread_t self,ft_event_t); int _automaton_await_n (ft_thread_t self,ft_event_t,int delay); int _automaton_generate (ft_thread_t self,ft_event_t); int _automaton_generate_value (ft_thread_t self,ft_event_t,void* val); int _automaton_get_value (ft_thread_t self,ft_event_t,int index,void **result); int _automaton_join (ft_thread_t self,ft_thread_t thread); int _automaton_join_n (ft_thread_t self,ft_thread_t thread,int delay); int _get_thread_state (ft_thread_t); void _set_thread_state (ft_thread_t,int state); void _set_thread_status (ft_thread_t,int status); void* _get_thread_local (ft_thread_t); void _set_thread_local (ft_thread_t,void *data); void* _get_thread_args (ft_thread_t); void _set_thread_return_code (ft_thread_t,int code); void _terminate (ft_thread_t); /****************************************************/ #define _SET_STATE(n) _set_thread_state (_self,n) #define _SET_STATUS(s) {_set_thread_status (_self,s); return;} /****************************************************/ #define _DEADLINE _get_thread_deadline (_self) #define _SET_DEADLINE(n) _set_thread_deadline (_self,n) #define _CURRENT_INSTANT _get_scheduler_instant (sched) /****************************************************/ #define _STAY_INST(delay)\ {\ int ret = _automaton_stay (_self,delay);\ if (ret == _STAY) return;\ else _set_thread_return_code (_self,ret);\ } /****************************************************/ #define _AWAIT(event)\ {\ int ret = _automaton_await (_self,event);\ if (ret == _STAY) return;\ else _set_thread_return_code (_self,ret);\ } #define _AWAIT_N(event,delay)\ {\ int ret = _automaton_await_n (_self,event,delay);\ if (ret == _STAY) return;\ else _set_thread_return_code (_self,ret);\ } /****************************************************/ #define _GENERATE(event) _automaton_generate (_self,event) #define _GENERATE_VALUE(event,val) _automaton_generate_value (_self,event,val) /****************************************************/ #define _GET_VALUE(event,index,result)\ {\ int ret = _automaton_get_value (_self,event,index,result);\ if (ret == _STAY) return;\ else _set_thread_return_code (_self,ret);\ } /****************************************************/ #define _JOIN(thread)\ {\ int ret = _automaton_join (_self,thread);\ if (ret == _STAY) return;\ else _set_thread_return_code (_self,ret);\ } #define _JOIN_N(thread,delay)\ {\ int ret = _automaton_join_n (_self,thread,delay);\ if (ret == _STAY) return;\ else _set_thread_return_code (_self,ret);\ } #endif /* _AUTOMATON_H */ ft_v1.0/src/broadcastlist.h0100644000374300000260000000045707477072670013307 0ustar fbtypedef struct broadcast_list_t *broadcast_list_t; broadcast_list_t _add_to_broadcast_list (ft_event_t, int pure, void *value, broadcast_list_t); void _destroy_broadcast_list (broadcast_list_t); void _generate_broadcast_list (broadcast_list_t); ft_v1.0/src/environment.h0100644000374300000260000000135607477072670013014 0ustar fbtypedef struct ft_environment_t *ft_environment_t; void _new_instant (ft_environment_t); ft_environment_t _environment_create (void); int _get_environment_eoi (ft_environment_t); void _set_environment_eoi (ft_environment_t,int b); int _get_environment_move (ft_environment_t); void _set_environment_move (ft_environment_t,int b); int _get_environment_instant (ft_environment_t); int _store_event_in_environment (ft_environment_t,int index,ft_event_t); void _add_to_timer (ft_environment_t,ft_thread_t); int _timer_size (ft_environment_t); ft_v1.0/src/event.h0100644000374300000260000000104107477072670011560 0ustar fbint _event_well_created (ft_event_t); ft_scheduler_t _get_event_scheduler (ft_event_t); int _event_is_generated (ft_event_t); int _fill_mask (int length,ft_event_t *events,int *mask); void _event_generate (ft_event_t); int _event_generate_value (ft_event_t,void *value); int _event_get_value (ft_event_t,int index,void **result); void _event_store_thread (ft_event_t,ft_thread_t); ft_v1.0/src/fthread.h0100644000374300000260000002223107477072670012060 0ustar fb/* fair threads API for C */ /* Copyright (C) 2002 Frederic Boussinot (Frederic.Boussinot@inria.fr) */ /* */ /* This program is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU Library General Public License */ /* as published by the Free Software Foundation; either version 2 */ /* of the License, or (at your option) any later version. */ /* */ /* This program 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 Library General Public License for more details. */ #ifndef _FT_THREAD_H #define _FT_THREAD_H #include /******** types ****************/ typedef struct ft_event_t *ft_event_t; typedef struct ft_thread_t *ft_thread_t; typedef struct ft_scheduler_t *ft_scheduler_t; typedef void (*ft_executable_t) (void*); typedef void (*ft_automaton_t) (ft_thread_t); /******** return codes ****************/ #define OK 0 // like for pthread: 0 means OK #define EBADMEM 1 // not enough memory #define ETIMEOUT 2 // timeout expired #define ENEXT 3 // no value generated during last intant #define EBADLINK 4 // bad linking to a scheduler #define EBADCREATE 5 // bad creation /* creation of schedulers, threads, and events */ ft_scheduler_t ft_scheduler_create (void); ft_thread_t ft_thread_create (ft_scheduler_t,ft_executable_t runnable,ft_executable_t cleanup,void *args); ft_thread_t ft_automaton_create (ft_scheduler_t,ft_automaton_t,ft_executable_t cleanup,void *args); ft_event_t ft_event_create (ft_scheduler_t); /* scheduler starting */ int ft_scheduler_start (ft_scheduler_t); /* orders given to schedulers */ int ft_scheduler_stop (ft_thread_t); int ft_scheduler_suspend (ft_thread_t); int ft_scheduler_resume (ft_thread_t); int ft_scheduler_broadcast (ft_event_t); int ft_scheduler_broadcast_value (ft_event_t,void *value); /* instructions executed by threads */ int ft_thread_generate (ft_event_t); int ft_thread_generate_value (ft_event_t,void *value); int ft_thread_cooperate (void); int ft_thread_cooperate_n (int num); int ft_thread_join (ft_thread_t); int ft_thread_join_n (ft_thread_t,int timeout); int ft_thread_await (ft_event_t); int ft_thread_await_n (ft_event_t,int timeout); int ft_thread_select (int length,ft_event_t *array,int *mask); int ft_thread_select_n (int length,ft_event_t *array,int *mask,int delay); int ft_thread_get_value (ft_event_t,int num,void **result); int ft_thread_link (ft_scheduler_t); int ft_thread_unlink (void); ft_thread_t ft_thread_self (void); ft_scheduler_t ft_thread_scheduler (void); /* termination of main */ void ft_exit (void); /* ft locks */ int ft_thread_mutex_lock (pthread_mutex_t*); int ft_thread_mutex_unlock (pthread_mutex_t*); /* pthread */ pthread_t ft_pthread (ft_thread_t); /************ macros for automata **********************/ #define AUTOMATON(name) _AUTOMATON(name) #define DEFINE_AUTOMATON(name) _DEFINE_AUTOMATON(name) #define BEGIN_AUTOMATON _BEGIN_AUTOMATON #define END_AUTOMATON _END_AUTOMATON #define GOTO(num) _GOTO(num) #define GOTO_NEXT _GOTO_NEXT #define IMMEDIATE(num) _IMMEDIATE(num) #define RETURN _THE_END #define SELF _SELF #define SET_LOCAL(data) _SET_LOCAL(data) #define LOCAL _LOCAL #define ARGS _ARGS #define RETURN_CODE _RETURN_CODE #define STATE(num) _STATE(num) #define STATE_AWAIT(num,event) _STATE(num) _AWAIT(event) #define STATE_AWAIT_N(num,event,n) _STATE(num) _AWAIT_N(event,n) #define STATE_GET_VALUE(num,event,n,result) _STATE(num) _GET_VALUE(event,n,result) #define STATE_STAY(num,n) _STATE(num) _STAY_INST(n) #define STATE_JOIN(num,thread) _STATE(num) _JOIN(thread) #define STATE_JOIN_N(num,thread,n) _STATE(num) _JOIN_N(thread,n) #define STATE_SELECT(num,len,array,mask) _STATE(num) _SELECT(len,array,mask) #define STATE_SELECT_N(num,len,array,mask,n) _STATE(num) _SELECT_N(len,array,mask,n) /********************************************** internal definitions: should not be used ***********************************************/ #define _AUTOMATON(x) void x (ft_thread_t) #define _DEFINE_AUTOMATON(name)\ void name (ft_thread_t _self)\ #define _BEGIN_AUTOMATON\ while (1) {\ int state = _get_thread_state (_self);\ if (state > 1000) {fprintf(stderr,"%d.",state); abort();}\ switch (state)\ { #define _STATE(n)\ case n: _SET_STATE(n); #define _END_AUTOMATON\ default: _THE_END\ }\ } #define _GOTO_NEXT {_SET_STATE(state+1); _SET_STATUS(_DONE);} #define _GOTO(n) {_SET_STATE(n); _SET_STATUS(_DONE);} #define _IMMEDIATE(n) {_SET_STATE(n); break;} #define _THE_END {_SET_STATE(-1); _terminate (_self); return;} /****************************************************/ #define _SELF _self #define _SET_LOCAL(data) _set_thread_local (_self,(void*)data) #define _LOCAL _get_thread_local (_self) #define _ARGS _get_thread_args (_self) #define _RETURN_CODE _get_thread_return_code (_self) /****************************************************/ /****************************************************/ #define _READY 0 // ready to run #define _BLOCKED 2 // waiting to be reexecuted during the same instant #define _DONE 3 // nothing to be done for current instant #define _TERMINATED 4 // nothing to be done in the future #define _SUSPENDED 5 // suspended, waiting to be resumed #define _WAIT 6 // waiting for an event to be generated #define _STAY 7 // automaton stays in the same state /****************************************************/ int _automaton_stay (ft_thread_t self,int delay); int _automaton_await (ft_thread_t self,ft_event_t); int _automaton_await_n (ft_thread_t self,ft_event_t,int delay); int _automaton_generate (ft_thread_t self,ft_event_t); int _automaton_generate_value (ft_thread_t self,ft_event_t,void* val); int _automaton_get_value (ft_thread_t self,ft_event_t,int index,void **result); int _automaton_join (ft_thread_t self,ft_thread_t thread); int _automaton_join_n (ft_thread_t self,ft_thread_t thread,int delay); int _automaton_select (ft_thread_t self,int length,ft_event_t *,int *mask); int _automaton_select_n (ft_thread_t self,int length,ft_event_t *,int *mask,int delay); int _get_thread_state (ft_thread_t); void _set_thread_state (ft_thread_t,int state); void _set_thread_status (ft_thread_t,int status); void* _get_thread_local (ft_thread_t); void _set_thread_local (ft_thread_t,void *data); void* _get_thread_args (ft_thread_t); int _get_thread_return_code (ft_thread_t); void _set_thread_return_code (ft_thread_t,int code); ft_scheduler_t _get_thread_scheduler (ft_thread_t); void _terminate (ft_thread_t); int _get_scheduler_eoi (ft_scheduler_t); void _set_scheduler_move (ft_scheduler_t); /****************************************************/ #define _SET_STATE(n) _set_thread_state (_self,n) #define _SET_STATUS(s) {_set_thread_status (_self,s); return;} /****************************************************/ #define _DEADLINE _get_thread_deadline (_self) #define _SET_DEADLINE(n) _set_thread_deadline (_self,n) #define _CURRENT_INSTANT _get_scheduler_instant (sched) /****************************************************/ #define _STAY_OR_PASS(ret)\ {int b = ret; if (b == _STAY) return; else _set_thread_return_code (_self,b);} #define _STAY_INST(delay) _STAY_OR_PASS(_automaton_stay (_self,delay)) #define _AWAIT(event) _STAY_OR_PASS(_automaton_await (_self,event)) #define _AWAIT_N(event,delay) _STAY_OR_PASS(_automaton_await_n (_self,event,delay)) #define _GET_VALUE(event,index,result) _STAY_OR_PASS(_automaton_get_value (_self,event,index,result)) #define _JOIN(thread) _STAY_OR_PASS(_automaton_join (_self,thread)) #define _JOIN_N(thread,delay) _STAY_OR_PASS(_automaton_join_n (_self,thread,delay)) #define _SELECT(len,array,mask) _STAY_OR_PASS(_automaton_select (_self,len,array,mask)) #define _SELECT_N(len,array,mask,delay) _STAY_OR_PASS(_automaton_select_n (_self,len,array,mask,delay)) #endif /* _FT_THREAD_H */ ft_v1.0/src/fthread_internal.h0100644000374300000260000000061307477072670013754 0ustar fb#include #include // the API #include "fthread.h" // lists #include "threadlist.h" #include "locklist.h" #include "broadcastlist.h" // event environment #include "environment.h" // thread, event, and scheduler #include "thread.h" #include "event.h" #include "scheduler.h" // verify that calls are correct #include "verify.h" // to trace pthread mutex use #include "trace.h" ft_v1.0/src/locklist.h0100644000374300000260000000034507477072670012271 0ustar fbtypedef struct lock_list_t *lock_list_t; lock_list_t _add_to_lock_list (pthread_mutex_t*,lock_list_t); lock_list_t _remove_from_lock_list (pthread_mutex_t*,lock_list_t); void _unlock_all (lock_list_t); ft_v1.0/src/scheduler.h0100644000374300000260000000121207477072670012415 0ustar fbint _scheduler_well_created (ft_scheduler_t); ft_thread_t _get_scheduler_self (ft_scheduler_t); ft_environment_t _get_scheduler_environment (ft_scheduler_t); int _get_scheduler_eoi (ft_scheduler_t); void _set_scheduler_move (ft_scheduler_t); int _get_scheduler_instant (ft_scheduler_t); int _store_event (ft_scheduler_t,int index,ft_event_t); void _store_in_timer (ft_scheduler_t,ft_thread_t); int _register_unlink_order (ft_thread_t); int _register_as_runnable (ft_thread_t); ft_v1.0/src/thread.h0100644000374300000260000000473507477072670011723 0ustar fb#define _READY 0 // ready to run #define _BLOCKED 2 // waiting to be reexecuted during the same instant #define _DONE 3 // nothing to be done for current instant #define _TERMINATED 4 // nothing to be done in the future #define _SUSPENDED 5 // suspended, waiting to be resumed #define _WAIT 6 // waiting for an event to be generated #define _STAY 7 // automaton stays in the same state int _thread_well_created (ft_thread_t); ft_scheduler_t _get_thread_scheduler (ft_thread_t); void _set_thread_scheduler (ft_thread_t,ft_scheduler_t); int _get_thread_status (ft_thread_t); void _set_thread_status (ft_thread_t,int status); int _get_thread_deadline (ft_thread_t); void _set_thread_deadline (ft_thread_t,int deadline); int _get_thread_state (ft_thread_t); void _set_thread_state (ft_thread_t,int state); void* _get_thread_args (ft_thread_t); ft_thread_t _make_thread (void); int _start_phase (ft_thread_t); void _stop_thread (ft_thread_t); void _lock_thread (ft_thread_t); void _unlock_thread (ft_thread_t); void _trace_thread (ft_thread_t); void _release (ft_thread_t,int status); void _add_lock (ft_thread_t,pthread_mutex_t*); void _remove_lock (ft_thread_t,pthread_mutex_t*); void _terminate (ft_thread_t); void _give_token_to (ft_thread_t); void _transmit_token (ft_thread_t source,ft_thread_t target); int _is_automaton (ft_thread_t); void* _get_thread_local (ft_thread_t); void _set_thread_local (ft_thread_t,void *data); int _get_thread_return_code (ft_thread_t); void _set_thread_return_code (ft_thread_t,int code); void _run_as_automaton (ft_thread_t); #define _POST_EVENT(event,self)\ _event_store_thread (event,self) #define _POST_TIMER(self,sched,deadline)\ {\ _set_thread_deadline (self,deadline);\ _store_in_timer (sched,self);\ } #define _CONTROL_TIMEOUT(deadline,sched) \ if (deadline <= _get_scheduler_instant (sched)) return ETIMEOUT ft_v1.0/src/threadlist.h0100644000374300000260000000124107477072670012604 0ustar fbtypedef struct thread_list_t *thread_list_t; typedef struct thread_cell_t *thread_cell_t; typedef int (*thread_list_map_t) (ft_thread_t); thread_list_t _create_thread_list (void); int _add_thread_list (thread_list_t,ft_thread_t); void _reset_thread_list (thread_list_t); void _apply_thread_list (thread_list_t,thread_list_map_t); void _trace_thread_list (thread_list_t); int _get_length_thread_list (thread_list_t); thread_cell_t _get_first_thread_list (thread_list_t); ft_thread_t _get_content_thread_cell (thread_cell_t); thread_cell_t _get_next_thread_cell (thread_cell_t); ft_v1.0/src/trace.h0100644000374300000260000000113607477072670011542 0ustar fb#define _TRACE(msg,lock) //fprintf(stderr,msg,(long)&lock) #define _PTH_LOCK(lock)\ {\ _TRACE("LOCK THREAD %ld\n",lock);\ pthread_mutex_lock (&lock);\ } #define _PTH_UNLOCK(lock)\ {\ _TRACE("UNLOCK THREAD %ld\n",lock);\ pthread_mutex_unlock (&lock);\ } #define _PTH_WAIT(cond,lock)\ {\ _TRACE("UNLOCK THREAD %ld (wait)\n",lock);\ pthread_cond_wait (&cond,&lock);\ _TRACE("LOCK THREAD %ld (wait)\n",lock);\ } #define _PTH_NOTIFY(cond,lock)\ {\ _TRACE("NOTIFY THREAD %ld\n",lock);\ pthread_cond_signal (&cond);\ } ft_v1.0/src/verify.h0100644000374300000260000000253407477072670011753 0ustar fb#define FT_MAGIC 123456789 #define _VERIFY_SCHEDULER_CREATION(sched)\ if (sched == NULL || !_scheduler_well_created (sched)) return EBADCREATE #define _VERIFY_EVENT_CREATION(event)\ if (event == NULL || !_event_well_created (event)) return EBADCREATE #define _VERIFY_THREAD_CREATION(thread)\ if (thread == NULL || !_thread_well_created (thread)) return EBADCREATE /* #define _VERIFY_EVENT_LINKING(event)\ {\ ft_thread_t self = ft_thread_self ();\ if (self == NULL || _get_thread_scheduler (self) != _get_event_scheduler (event)) \ return EBADLINK;\ } */ #define _VERIFY_EVENT_LINKING_TO_SCHEDULER(event,sched)\ if (sched == NULL || sched != _get_event_scheduler (event)) return EBADLINK #define _VERIFY_THREAD_LINKING(thread)\ if (thread == NULL || _get_thread_scheduler (thread) == NULL) return EBADLINK #define _VERIFY_THREAD_UNLINKING(thread)\ if (thread == NULL || _get_thread_scheduler (thread) != NULL) return EBADLINK #define _VERIFY_THREAD_CREATION_AND_LINK(thread)\ {\ if (thread == NULL || !_thread_well_created (thread)) return EBADCREATE;\ if (_get_thread_scheduler (thread) == NULL) return EBADLINK;\ } #define _VERIFY_EVENT_CREATION_AND_SCHEDULER(event,sched)\ {\ if (event == NULL || !_event_well_created (event)) return EBADCREATE;\ if (sched == NULL || sched != _get_event_scheduler (event)) return EBADLINK;\ } ft_v1.0/src/makefile0100644000374300000260000000364707477072670012004 0ustar fbINCL_DIR = ../include LIB_DIR = ../lib ############################################################## MAKE = make CC = gcc AR = ar RANLIB = ranlib ############################################################## LIBS = -lfthread -lpthread #LIBS = -lposix4 -lfthread -lpthread # for solaris ############################################################## ############################################################## CFLAGS = -Wall -O3 -D_REENTRANT ############ Basic libraries ################################# LIB_NAME = fthread LIBFT = lib$(LIB_NAME).a ############ C code to executable code ######################## .c.o : $(CC) $(CFLAGS) -c $< ############ The h files ###################################### HFILES = fthread.h fthread_internal.h \ event.h thread.h scheduler.h \ broadcastlist.h locklist.h threadlist.h \ environment.h trace.h verify.h ############ The C files ###################################### CFILES = event.c thread.c scheduler.c \ broadcastlist.c locklist.c threadlist.c \ environment.c automaton.c instruction.c ############ The object files ################################## OBJS = event.o thread.o scheduler.o \ broadcastlist.o locklist.o threadlist.o \ environment.o automaton.o instruction.o ############ Make entries ###################################### all: lib lib: $(HFILE) $(OBJS) $(AR) r $(LIBFT) $(OBJS) - $(RANLIB) $(LIBFT) install: lib cp $(LIBFT) $(LIB_DIR) cp fthread.h $(INCL_DIR) clean: - rm -rf *.o *~ $(LIBFT) a.out ############ Auxiliary ######################################## TEST = test.c lines: wc -l $(CFILES) $(HFILES) test:all $(CC) $(CFLAGS) -I. -L. $(TEST) $(LIBS) a.out ############ Dependencies ######################################## $(OBJS): $(HFILE) ############ end of makefile ##################################### ft_v1.0/man/0040755000374300000260000000000007477072670010261 5ustar fbft_v1.0/man/ft_event_create.man0100644000374300000260000000327707477072670014121 0ustar fb.if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .. .TH ft_event_create 1 .SH NAME ft_event_create \- create a new event .SS SYNOPSIS .Sp .nf \fB#include\fR ft_event_t \fBft_event_create\fR (ft_scheduler_t sched); .Sp .fi .SS DESCRIPTION \fBft_event_create\fR returns a new event which is created in the scheduler \fBsched\fR. The event can be generated by \fBft_event_generate\fR or \fBft_scheduler_broadcast\fR, and it can awaited by \fBft_event_await\fR. .SS RETURN VALUES On success, the new event is returned and set to absent; \fBNULL\fR is returned otherwise. .SS ERRORS .RS 3 .TP \&\fBNULL\fR The event cannot be created or the scheduler \fBsched\fR is not correctly created. .RE .SS SEE ALSO \fBft_event_generate\fR (3), \fBft_scheduler_broadcast\fR (3), \fBft_event_await\fR (3). .SH AUTHOR ft_v1.0/man/ft_exit.man0100644000374300000260000000231707477072670012420 0ustar fb.if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .. .TH ft_exit 1 .SH NAME ft_exit \- exit a thread .SS SYNOPSIS .Sp .nf \fB#include\fR void \fBft_exit\fR (void); .Sp .fi .SS DESCRIPTION \fBft_exit\fR forces the calling thread to terminate. .SS RETURN VALUES The function \fBft_exit\fR never returns. .SH AUTHOR ft_v1.0/man/ft_pthread.man0100644000374300000260000000233407477072670013075 0ustar fb.if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .. .TH ft_pthread 1 .SH NAME ft_pthread \- pthread basis .SS SYNOPSIS .Sp .nf \fB#include\fR pthread_t \fBft_pthread\fR (ft_thread_t thread); .Sp .fi .SS DESCRIPTION The function \fBft_pthread\fR returns the pthread on which the fair thread \fBthread\fR is built. .SH AUTHOR ft_v1.0/man/ft_scheduler_broadcast.man0100644000374300000260000000353207477072670015447 0ustar fb.if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .. .TH ft_scheduler_broadcast, 1 .SH NAME ft_scheduler_broadcast, ft_scheduler_broadcast_value \- broadcast of events .SS SYNOPSIS .Sp .nf \fB#include\fR int \fBft_scheduler_broadcast\fR (ft_event_t evt); int \fBft_scheduler_broadcast_value\fR (ft_event_t evt,void *val); .Sp .fi .SS DESCRIPTION \fBft_scheduler_broadcast\fR asks the scheduler of the event \fBevt\fR to broadcast it. The event will be generated during the next instant of the scheduler. The value \fBval\fR is associated to \fBevt\fR when the function \fBft_scheduler_broadcast_value\fR is used. .SS RETURN VALUES On success, the value 0 is returned. On error, a non-zero error code is returned. .SS ERRORS .RS 3 .TP \&\fBBADCREATE\fR The event \fBevt\fR is not correctly created. .RE .RS 3 .TP \&\fBBADMEM\fR Not enough memory (the scheduler cannot store the broadcast order). .RE .SS SEE ALSO \fBft_event_create\fR (3). .SH AUTHOR ft_v1.0/man/ft_scheduler_create.man0100644000374300000260000000360707477072670014753 0ustar fb.if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .. .TH ft_scheduler_create, 1 .SH NAME ft_scheduler_create, ft_scheduler_start \- create and start a new scheduler .SS SYNOPSIS .Sp .nf \fB#include\fR ft_scheduler_t \fBft_scheduler_create\fR (void); int \fBft_scheduler_start\fR (ft_scheduler_t sched); .Sp .fi .SS DESCRIPTION \fBft_scheduler_create\fR returns a new scheduler that will run the threads created in it, using \fBft_thread_create\fR. The new scheduler \fBsched\fR starts running when the function \fBft_scheduler_start\fR is called. .SS RETURN VALUES On success \fBft_scheduler_create\fR returns the new scheduler; \fBNULL\fR is returned otherwise. On success the value 0 is returned by \fBft_scheduler_start\fR and a non-zero error code is returned otherwise. .SS ERRORS .RS 3 .TP \&\fBNULL\fR The scheduler cannot be created. .RE .RS 3 .TP \&\fBBADCREATE\fR The scheduler \fBsched\fR is not correctly created when started. .RE .SS SEE ALSO \fBft_thread_create\fR (3). .SH AUTHOR ft_v1.0/man/ft_scheduler_stop.man0100644000374300000260000000513307477072670014471 0ustar fb.if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .. .TH ft_scheduler_stop, 1 .SH NAME ft_scheduler_stop, ft_scheduler_suspend, ft_scheduler_resume \- control threads running in a scheduler .SS SYNOPSIS .Sp .nf \fB#include\fR int \fBft_scheduler_stop\fR (ft_thread_t th); int \fBft_scheduler_suspend\fR (ft_thread_t th); int \fBft_scheduler_resume\fR (ft_thread_t th); .Sp .fi .SS DESCRIPTION .P \fBft_scheduler_stop\fR asks the scheduler running the thread \fBth\fR to force termination of it. Nothing special happens if the thread is already terminated. Otherwise, at the begining of the next instant, \fBth\fR executes the function \fBcleanup\fR if it exists, or otherwise terminates immediately. .P \fBft_scheduler_suspend\fR asks the scheduler running the thread \fBth\fR to suspend execution of it. The suspension will become actual at the beginning of the next instant of the scheduler. .P \fBft_scheduler_resume\fR asks the scheduler running the thread \fBth\fR to resume execution of it. The resume will become actual at the beginning of the next instant of the scheduler. Suspension has higher priority than resume: if a thread is suspended and resumed during the same instant, then the thread will be suspended. A suspended thread which is stopped is first resumed. .SS RETURN VALUES On success, the value 0 is returned. On error, a non-zero error code is returned. .SS ERRORS .RS 3 .TP \&\fBBADCREATE\fR The thread \fBth\fR is not correctly created. .RE .RS 3 .TP \&\fBBADLINK\fR The thread \fBth\fR is unlinked. .RE .RS 3 .TP \&\fBBADMEM\fR Not enough memory (the order cannot be stored by the scheduler). .RE .SS SEE ALSO \fBft_thread_create\fR (3), \fBft_scheduler_create\fR (3). .SH AUTHOR ft_v1.0/man/ft_thread_cooperate.man0100644000374300000260000000315007477072670014753 0ustar fb.if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .. .TH ft_thread_cooperate, 1 .SH NAME ft_thread_cooperate, ft_thread_cooperate_n \- cooperate operations .SS SYNOPSIS .Sp .nf \fB#include\fR int \fBft_thread_cooperate\fR (void); int \fBft_thread_cooperate_n\fR (int n); .Sp .fi .SS DESCRIPTION \fBft_thread_cooperate\fR makes the calling thread cooperate by returning the control to the scheduler in which it is running. The call \fBft_thread_cooperate_n (k)\fR is equivalent to \fBfor (i=0;i ft_thread_t \fBft_thread_create\fR (ft_scheduler_t sched, void (*runnable)(void*), void (*cleanup)(void*), void *args); .Sp .fi .SS DESCRIPTION .P \fBft_thread_create\fR returns a new thread of control and links it to the scheduler \fBsched\fR. While linked in \fBsched\fR, the new thread will execute concurrently with the other threads linked in it. Actual starting of the new thread is asynchronous with the creation. The new thread applies the function \fBrunnable\fR passing it \fBargs\fR as first argument. The new thread terminates when it executes \fBft_exit\fR or when it returns from the \fBrunnable\fR function. .P When stopped (by \fBft_scheduler_stop\fR), the new thread applies the function \fBcleanup\fR, if it is not \fBNULL\fR, passing it \fBargs\fR as first argument. .P A pthread is created with each fair thread. This pthread is initially attached. It can be detached using \fBft_pthread\fR and \fBpthread_detach\fR. .SS RETURN VALUES On success, \fBft_thread_create\fR returns a new thread; \fBNULL\fR is returned otherwise. .SS ERRORS .RS 3 .TP \&\fBNULL\fR The thread cannot be created, or the scheduler \fBsched\fR is not correctly created. .RE .SS SEE ALSO \fBft_exit\fR (3), \fBft_scheduler_create\fR (3), \fBft_scheduler_stop\fR (3), \fBft_pthread\fR (3). .SH AUTHOR ft_v1.0/man/ft_thread_generate.man0100644000374300000260000000655707477072670014602 0ustar fb.if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .. .TH ft_thread_generate, 1 .SH NAME ft_thread_generate, ft_thread_await \- generate and await an event .SS SYNOPSIS .Sp .nf \fB#include\fR int \fBft_thread_generate\fR (ft_event_t evt); int \fBft_thread_generate_value\fR (ft_event_t evt,void *val); int \fBft_thread_await\fR (ft_event_t evt); int \fBft_thread_await_n\fR (ft_event_t evt,int n); int \fBft_thread_select\fR (int len,ft_event_t *array,int *mask); int \fBft_thread_select_n\fR (int len,ft_event_t *array,int *mask,int timeout); .Sp .fi .SS DESCRIPTION \fBft_thread_generate\fR generates the event \fBevt\fR for the current instant of the scheduler in which the calling thread is running. The event is thus present for this instant; it will be automatically reset to absent at the begining of the next instant. The value \fBval\fR is associated to \fBevt\fR when \fBft_thread_generate_value\fR is used. .P \fBft_thread_await\fR suspends the calling thread until \fBevt\fR becomes generated in the scheduler in which it is running. The waiting takes as many instants as the generation of \fBevt\fR takes. \fBft_thread_await_n (evt,k)\fR is similar to \fBft_thread_await (evt)\fR except that the waiting of \fBevt\fR lasts at most \fBk\fR instants. .P \fBft_thread_select\fR suspends the calling thread until one element of \fBarray\fR becomes generated in the scheduler in which the thread is running; \fBarray\fR should be of length \fBk\fR. On resumption, \fBmask\fR which is an array of \fBk\fR integers, is set accordingly: \fBmask[i]\fR is 1 if \fBarray[i]\fR was generated; \fBmask[i]\fR is 0, otherwise. \fBft_thread_select_n (k,array,mask,p)\fR is similar to \fBft_thread_select (k,array,mask)\fR except that the waiting lasts at most \fBp\fR instants. .SS RETURN VALUES On success the value 0 is returned and a non-zero error code is returned on error. .SS ERRORS .RS 3 .TP \&\fBBADCREATE\fR The exist an event (either \fBevt\fR or an element of \fBarray\fR) which is not correctly created. .RE .RS 3 .TP \&\fBBADLINK\fR Either the calling thread is unlinked, or the scheduler of the calling thread and the one of a considered event (\fBevt\fR or an element of \fBarray\fR) are different. .RE .RS 3 .TP \&\fBBADMEM\fR Not enough memory (can only occur with \fBft_thread_generate_value\fR). .RE .RS 3 .TP \&\fBTIMEOUT\fR The timeout is reached. .RE .SS SEE ALSO \fBft_event_create\fR (3), \fBft_thread_get_value\fR (3). .SH AUTHOR ft_v1.0/man/ft_thread_get_value.man0100644000374300000260000000440007477072670014744 0ustar fb.if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .. .TH ft_thread_get_value 1 .SH NAME ft_thread_get_value \- get the nth value associated to a generated event .SS SYNOPSIS .Sp .nf \fB#include\fR int \fBft_thread_get_value\fR (ft_event_t evt,int n,void **result); .Sp .fi .SS DESCRIPTION \fBft_thread_get_value\fR returns the \fBn\fRth value associated during the current instant to the event \fBevt\fR through calls of \fBft_event_generate_value\fR or \fBft_scheduler_broadcast_value\fR. If such a value exists, \fBft_thread_get_value\fR sets \fBresult\fR with a reference to it and terminates immediately (that is, during the current instant). Otherwise, it terminates at the next instant (returning \fBNEXT\fR) and \fBresult\fR is then set to \fBNULL\fR. .SS RETURN VALUES On success, the value 0 is returned (during the current instant). Otherwise, a non-zero error code is returned. .SS ERRORS .RS 3 .TP \&\fBBADCREATE\fR The event \fBevt\fR is not correctly created. .RE .RS 3 .TP \&\fBBADLINK\fR Either the calling thread is unlinked, or the scheduler of the calling thread and the one of \fBevt\fR are different. .RE .RS 3 .TP \&\fBNEXT\fR Less than \fBn\fR values where actually associated to generations of \fBevt\fR during the previous instant. .RE .SS SEE ALSO \fBft_thread_generate_value\fR (3), \fBft_scheduler_broadcast_value\fR (3). .SH AUTHOR ft_v1.0/man/ft_thread_join.man0100644000374300000260000000402207477072670013730 0ustar fb.if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .. .TH ft_thread_join, 1 .SH NAME ft_thread_join, ft_thread_join_n \- wait for termination of another thread .SS SYNOPSIS .Sp .nf \fB#include\fR int \fBft_thread_join\fR (ft_thread_t th); int \fBft_thread_join_n\fR (ft_thread_t th,int n); .Sp .fi .SS DESCRIPTION \fBft_thread_join\fR suspends the execution of the calling thread until the thread \fBth\fR terminates (either by reaching the end of the function it run, or by executing ft_exit) or is stopped (by ft_scheduler_stop). If \fBth\fR is already terminated, the call immediately terminates. \fBft_thread_join_n (th,i)\fR waits for at most \fBi\fR instants for termination of \fBth\fR. .SS RETURN VALUES On success, the value 0 is returned. On error, a non-zero error code is returned. .SS ERRORS .RS 3 .TP \&\fBBADCREATE\fR The thread \fBth\fR is not correctly created. .RE .RS 3 .TP \&\fBBADLINK\fR The calling thread is unlinked. .RE .RS 3 .TP \&\fBTIMEOUT\fR The timeout is reached before the thread is joined. .RE .SS SEE ALSO \fBft_thread_create\fR (3), \fBft_exit\fR (3), \fBft_scheduler_stop\fR (3). .SH AUTHOR ft_v1.0/man/ft_thread_link.man0100644000374300000260000000453707477072670013741 0ustar fb.if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .. .TH ft_thread_link, 1 .SH NAME ft_thread_link, ft_thread_unlink \- link and unlink a thread .SS SYNOPSIS .Sp .nf \fB#include\fR int \fBft_thread_unlink\fR (void); int \fBft_thread_link\fR (ft_scheduler_t sched); .Sp .fi .SS DESCRIPTION \fBft_thread_unlink\fR unlinks the calling thread from the scheduler which is running it. Execution of the thread suspends until the begining of the next instant of the scheduler. At that point, the thread turns into a standard thread, not linked to any scheduler, and it resumes execution autonomously. Initialy, a fair thread is automatically linked to the scheduler in which it is created (by \fBft_thread_create\fR). \fBft_thread_link\fR links the calling thread to the scheduler \fBsched\fR. The thread must be unlinked. Execution suspends until \fBsched\fR gives the control to the thread; then, the thread resumes execution, being scheduled by \fBsched\fR. .SS RETURN VALUES On success, the value 0 is returned. On error, a non-zero error code is returned. .SS ERRORS .RS 3 .TP \&\fBBADCREATE\fR The scheduler \fBsched\fR is not correctly created. .RE .RS 3 .TP \&\fBBADLINK\fR The calling thread is already linked while running \fBft_thread_link\fR, or it is unlinked while running \fBft_thread_unlink\fR. .RE .RS 3 .TP \&\fBBADMEM\fR Not enough memory (the scheduler cannot store the link/unlink order). .RE .SS SEE ALSO \fBft_thread_create\fR (3). .SH AUTHOR ft_v1.0/man/ft_thread_mutex_lock.man0100644000374300000260000000420007477072670015141 0ustar fb.if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .. .TH ft_thread_mutex_lock, 1 .SH NAME ft_thread_mutex_lock, ft_thread_mutex_unlock \- mutexes for fair threads .SS SYNOPSIS .Sp .nf \fB#include\fR int \fBft_thread_mutex_lock\fR (pthread_mutex_t *mutex); int \fBft_thread_mutex_unlock\fR (pthread_mutex_t *mutex); .Sp .fi .SS DESCRIPTION For unlinked threads, \fBft_thread_mutex_lock\fR is like \fBpthread_mutex_lock\fR and \fBft_thread_mutex_unlock\fR is like \fBpthread_mutex_unlock\fR. .P For linked threads, \fBft_thread_mutex_lock\fR suspends the calling thread until \fBmutex\fR can be locked. Thus, while \fBmutex\fR is unavailable, other threads in the scheduler can continue to run (this would not be the case if \fBpthread_mutex_lock\fR where used instead of \fBft_thread_mutex_lock\fR). All locks owned by a thread are automatically released when it terminates or when it is stopped. .SS RETURN VALUES On success \fBft_thread_mutex_lock\fR and \fBft_thread_mutex_unlock\fR both return the value 0. On error, a non-zero error code is returned. .SS ERRORS Errors returned are the ones returned by \fBpthread_mutex_lock\fR and \fBpthread_mutex_unlock\fR. .SS SEE ALSO \fBft_thread_link\fR (3), \fBft_thread_unlink\fR (3). .SH AUTHOR ft_v1.0/man/ft_thread_self.man0100644000374300000260000000306407477072670013727 0ustar fb.if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .. .TH ft_thread_self, 1 .SH NAME ft_thread_self, ft_thread_scheduler \- get the calling thread and scheduler .SS SYNOPSIS .Sp .nf \fB#include\fR ft_thread_t \fBft_thread_self\fR (void); ft_scheduler_t \fBft_thread_scheduler\fR (void); .Sp .fi .SS DESCRIPTION \fBft_thread_self\fR returns the calling thread. \fBft_thread_scheduler\fR returns the scheduler of the calling thread. .SS ERRORS The value \fBNULL\fR is returned by \fBft_thread_self\fR when the calling thread is not correctly created, or by \fBft_thread_scheduler\fR when the calling thread is not correctly created or is unlinked. .SH AUTHOR ft_v1.0/doc/0040755000374300000260000000000007477072670010253 5ustar fbft_v1.0/doc/ft-1.html0100644000374300000260000002043307477072670011707 0ustar fb 1. Introduction

1. Introduction

Browsing

Home: Fair Threads in C

Previous chapter:
Next chapter: Rationale


Introduction

Difficulties of Threads
The Fair Threads Proposal


Chapters

1. Introduction
2. Rationale
3. API Overview
4. API
5. Examples
6. Related Work
7. Conclusion
8. Man Pages


Threads are generally considered to be well adapted for systems made of heavy-computing tasks run in a preemptive context and needing few communications and synchronizations. This is typically the case of Web servers, in which a thread (usually picked out from a pool of available threads) is associated to each new request. In such contexts, advantages of threads are clear:
  • Modularity is increased, as threads can be naturally used for coding independant sub-parts of the system.
  • Programs can be run by multiprocessors machines without any change. Thus, multithreaded systems immediately take benefit from SMP architectures, which become now widely available.
  • Blocking I/Os do not need special attention of any kind. Indeed, as the scheduler is preemptive, there is no risk that a thread blocked forever on an I/O operation will also block the rest of the system.
Difficulties of Threads

The benefit of using threads is less clear for systems made of tasks needing strong synchronizations or a lot of communications. Indeed, in a preemptive context, to communicate or to synchronize generally implies the need to protect some data involved in the communication or in the synchronization. Locks are often used for this purpose, but they have a cost and are error-prone (possibilities of deadlocks).

Pure cooperative threads (sometimes called green-threads) are more adapted for highly communicating tasks. Indeed, data protection is no more needed, and one can avoid the use of locks. Moreover, cooperative threads have clear and simple semantics, and are thus easier to program and to port. However, while cooperative threads can be efficiently implemented at user level, they cannot benefit from multiprocessor machines. Moreover, they need special means to deal with blocking I/O.

Actually, programming with threads is difficult because threads generally have very "lose" semantics. This is particularly true with preemptive threads because their semantics strongly relies on the scheduling policy. The semantics of threads also depends on others aspects, as, for example, the way threads priorities are mapped at the kernel level.

Threads take time to create, and need a rather large amount of memory to execute. Moreover, the number of native threads than can be created is often limited by the system. Several techniques can be used to get round these problems, specially when large numbers of short-lived components are needed. Among these techniques are thread-pooling, to limit the number of created threads, and the use of small pieces of code, sometimes called "chores" or "chunks", which can be executed in a simpler way than threads are.


The Fair Threads Proposal

FairThreads proposes to overcome the difficulties of threads by giving users the possibility to chose the context, cooperative or preemptive, in which threads are executed. More precisely, FairThreads defines schedulers which are cooperative contexts to which threads can dynamically link or unlink. All threads linked to the same scheduler are executed in a cooperative way, and at the same pace. Threads which are not linked to any scheduler are executed by the OS in a preemptive way, at their own pace. An important point is that FairThreads offers programming constructs for linking and unlinking threads.

FairThreads has the following main characteristics:

  • It allows programs to benefit from multiprocessors machines. Indeed, schedulers and unlinked threads can be run in real parallelism, on distinct processors.
  • It allows users to stay in a purely cooperative context by linking all the threads to the same scheduler. In this case, systems are completely deterministic and have a simple and clear semantics.
  • Blocking I/Os can be implemented in a very simple way, using unlinked threads.
  • It defines instants shared by all the threads which are linked to the same scheduler. Thus, all threads linked to the same scheduler execute at the same pace, and there is an automatic synchronization at the end of each instant.
  • It introduces events which are instantaneously broadcast to all the threads linked to a scheduler; events are a modular and powerful mean for threads to synchronize and communicate.
  • It defines automata to deal with small, short-lived tasks, which do not need the full power of native threads. Automata have lightweight implementation and are not submitted to some limitations that native threads have.

This paper describes FairThreads in the context of C, implemented on top of the Pthreads library.

The rest of the paper is organized as follows: section 2 presents rationale for the design of FairThreads. An overwiew of the API of FairThreads is given in section 3. Section 4 contains the full API. Some examples are described in section 5. Related work is considered in section 6. Finally, section 7 concludes the paper. Man pages of FairThreads are given in annex.



This page has been generated by
Scribe.
Last update Tue Jun 4 10:09:20 2002
ft_v1.0/doc/ft-2.html0100644000374300000260000002366607477072670011723 0ustar fb 2. Rationale

2. Rationale

Browsing

Home: Fair Threads in C

Previous chapter: Introduction
Next chapter: API Overview


Rationale

Synchronized Areas
Cooperative Scheduling
Preemptive Scheduling
Automata


Chapters

1. Introduction
2. Rationale
3. API Overview
4. API
5. Examples
6. Related Work
7. Conclusion
8. Man Pages


In FairThreads, schedulers can be seen as synchronization servers, in which linked threads automatically synchronize at the end of each instant. However, in order to synchronize, linked threads must behave fairly and cooperate with the other threads by returning the control to the scheduler. Thus, linked threads are basically cooperative threads. Schedulers can also be seen as event servers as they are in charge of broadcasting generated events to all the linked threads. In this way, a fair scheduler defines a kind of synchronized area made of cooperative threads running at the same pace, and communicating through broadcast events.
Synchronized Areas

A synchronized area can quite naturally be defined to manage some shared data that has to be accessed by several threads. In order to get access to the data, a thread has first to link to the area, and then it becomes scheduled by the area and can thus get safe access to the data. Indeed, as the scheduling is cooperative, there is no risk for the thread to be preempted during an access to the data. The use of a synchronized area is, in this case, an alternative to the use of locks. A synchronized area can also play the role of a location that threads can join when some kind of communication or synchronization is needed.

FairThreads allows programmers to decompose complex systems in several threads and areas to which threads can link dynamically, following their needs. Moreover, a thread can be unlinked, that is totally free from any synchronization provided by any schedulers defined in the system. Of course, unlinked threads cannot benefit from broadcast events. Unlinked threads are run in the preemptive context of the OS, and are thus just standard preemptive threads. Data shared by unlinked threads have to be protected by locks, in the standard way.


Cooperative Scheduling

Basically, a linked fair thread is a cooperative thread which can synchronize with other fair threads using events and can communicate with them through values associated to these events. The scheduler to which the fair thread is linked gives it the possibility to get the processor. All threads linked to the scheduler get equal right to execute. More precisely, fair schedulers define instants during which all threads linked to it run up to their next cooperation point. There are only two kinds of cooperation points: explicit ones which are calls to the cooperate() function, and implicit ones where threads are waiting for events. A fair scheduler broadcasts events to all fair threads linked to it. Thus, all threads linked to the same scheduler see the presence and the absence of events in exactly the same way. Moreover, values associated to events are also broadcast. Actually, events are local to the scheduler in which they are created, and are non-persistent data which are reset at the beginning of each new instant.

Modularity

Events are a powerful synchronisation and communication mean which simplifies concurrent programming while reducing risks of deadlocks. Events are used when one wants one or more threads to wait for a condition, without polling a variable to determine when the condition is fulfilled. Broadcast is a mean to get modularity, as the thread which generates an event has nothing to know about potentially receivers of it. Fairness in event processing means that all threads waiting for an event always receive it during the same instant it is generated; thus, a thread leaving control on a cooperation point does not risk to loose an event generated later in the same instant.


Determinism

Cooperative frameworks are less undeterministic than preemptive ones, as in cooperative frameworks preemption cannot occurs in an uncontrolled way. Actually, FairThreads puts the situation to an extreme point, when considering linked threads: linked threads are chosen for execution following a strict round-robin algorithm which leads to deterministic systems. This can be a great help in programming and debugging.


No Priorities

Priorities are meaningless for linked threads which always have equal rights to execute. Absence of priorities also contributes to simplify programming.



Preemptive Scheduling

Basically, unlinked threads are standard native preemptive threads. They are introduced in FairThreads for two main reasons. First, using unlinked threads, users can program non-blocking I/Os in a very simple way. Without this kind of I/Os, programming would become problematic. Second, unlinked threads can be run by distinct processors. The use of unlinked threads is a plus in multiprocessors contexts.


Automata

FairThreads proposes automata to deal with auxiliary tasks, such as waiting for an event to stop a thread, that do not need the full power of a dedicated native thread to execute. An automaton is a special linked fair thread which executes using the native thread of the scheduler to which it is linked. Thus, an automaton does not have its own execution stack that it could use to store its execution state. As a consequence, it can be implemented more efficiently than threads are.

Basically, automata are lists of states which are elementary pieces of sequential code. The current state is stored by the automaton and execution starts from it at the begining of the instant. Execution leaves the current state when an explicit jump to another state is executed. When the state terminates without any explicit jump, execution automatically proceeds to the next state. Execution of the automaton terminates when the last state is exited. Thus, the fine-grain sequentiality of execution inside states is not memorized by automata, only the coarse-grain sequentiality of states execution is.

Events can be used without restriction in automata. There is a special state to await an event: execution stays in this state until the event is generated.



This page has been generated by
Scribe.
Last update Tue Jun 4 10:09:20 2002
ft_v1.0/doc/ft-3.html0100644000374300000260000003614307477072670011716 0ustar fb 3. API Overview

3. API Overview

Browsing

Home: Fair Threads in C

Previous chapter: Rationale
Next chapter: API


API Overview

3.1 Creation
3.2 Orders
3.3 Basic Primitives
3.4 Managing Events
3.5 Linking
3.6 Automata
3.7 Miscelaneous


Chapters

1. Introduction
2. Rationale
3. API Overview
4. API
5. Examples
6. Related Work
7. Conclusion
8. Man Pages


3.1 Creation

Schedulers

FairThreads explicitely introduces schedulers, of type ft_scheduler_t. Before being used, a scheduler must be created by calling the function ft_scheduler_create.

In order to be executed, a scheduler must be started by a call to the function ft_scheduler_start. Note that several schedulers can be used without problem simultaneously in the same program.


Threads

Fair threads are of type ft_thread_t. The call ft_thread_create(s,r,c,a) creates a thread in the scheduler s. The thread is automatically started as soon as it is created. The function r is executed by the thread, and the parameter a is transmitted to it. The function c is executed by the thread if it is stopped (by ft_scheduler_stop). The parameter a is also transmitted to it, if this happens.


Events

Events are of the type ft_event_t. An event is created by calling the function ft_event_create which takes as parameter the scheduler in charge of it.


Automata

Automata are fair threads of the type ft_thread_t created with the function ft_automaton_create. The thread returned by ft_automaton_create(s,r,c,a) is executed as an automaton by the scheduler s. The function r executed by the automaton must be defined with the macro DEFINE_AUTOMATON.



3.2 Orders

Control of Threads

The call ft_scheduler_stop(t) gives to the scheduler which executes the thread t the order to stop it. The stop will become actual at the begining of the next instant of the scheduler, in order to assure that t is in a stable state when stopped.

The call ft_scheduler_suspend(t) gives to the scheduler which executes t the order to suspend t. The suspension will become actual at the begining of the next instant of the scheduler. The function ft_scheduler_resume is used to resume execution of suspended threads.


Broadcast of Events

The function ft_scheduler_broadcast(e) gives to the scheduler of the event e the order to broadcast it to all threads running in the scheduler. The event will be actually generated at the begining of the next instant of the scheduler. The call ft_scheduler_broadcast_value(e,v) associates the value v to e (v can be read using ft_thread_get_value).



3.3 Basic Primitives

Cooperation

The call ft_thread_cooperate() is the explicit way for the calling thread to return control to the scheduler running it. The call ft_thread_cooperate_n(i) is equivalent to a sequence of i calls ft_thread_cooperate().


Termination

The call ft_thread_join(t) suspends the execution of the calling thread until the thread t terminates (either normally or because it is stopped). Note that t needs not to be linked or running in the scheduler of the calling thread. With ft_thread_join_n(t,i) the suspension takes at most i instants.



3.4 Managing Events

Generating Events

The call ft_thread_generate(e) generates the event e in the scheduler which was associated to it, when created. The call ft_thread_generate_value(e,v) adds v to the list of values associated to e during the current instant (these values can be read using ft_thread_get_value).


Awaiting Events

The call ft_thread_await(e) suspends the execution of the calling thread until the generation of the event e. Execution is resumed as soon as the event is generated. With ft_thread_await_n(e,i), the waiting takes at most i instants.


Selecting Events

The call ft_thread_select(k,array,mask) suspends the execution of the calling thread until the generation of one element of array which is an array of k events. Then, mask, which is an array of k boolean values, is set accordingly. With ft_thread_select_n(k,array,mask,i), the waiting takes at most i instants.


Getting Events Values

The call ft_thread_get_value(e,i,r) is an attempt to get the ith value associated to the event e during the current instant. If such a value exists, it is returned in r and the call immediately terminates. Otherwise, the value NULL is returned at the next instant. The return code of the call indicates if the call was sucessful or not.



3.5 Linking

Link and Unlink

The call ft_thread_unlink() unlinks the calling thread t from the scheduler in which it was previously running. Then, t will no longer synchronize, instant after instant, with other threads linked to the scheduler. Actually, after unlinking, t behaves as a standard native thread.

The call ft_thread_link(s) links the calling thread to the scheduler s. The calling thread must be unlinked when executing the call. The linkage becomes actual at the begining of the next instant of s.


Locks

In presence of unlinked threads, locks can be needed to protect data shared between unlinked and linked threads. Standard mutexes are used for this purpose. The call ft_thread_mutex_lock(p), where p is a mutex, suspends the calling thread until the moment where p can be locked. The lock is released using ft_thread_mutex_unlock. Locks owned by a thread are automatically released when the thread terminates definitively or is stopped.



3.6 Automata

Automata are coded using macros. Here are the macros to define the automaton structure:

  • AUTOMATON(aut) declares the automaton aut.
  • DEFINE_AUTOMATON(aut) starts definition of the automaton aut.
  • BEGIN_AUTOMATON starts the state list.
  • END_AUTOMATON ends the state list.
The following macros start the state whose number is num:
  • STATE(num) introduces a standard state.
  • STATE_AWAIT(num,event) and STATE_AWAIT_N(num,event,delay) are states to await event.
  • STATE_JOIN(num,thread) and STATE_JOIN_N(num,thread,delay) are states to join thread.
  • STATE_STAY(num,n) is a state which keeps execution in it for n instants.
  • STATE_GET_VALUE(num,event,n,result) is a state to get the nth value associated to event.
  • STATE_SELECT(num,n,array,mask) and STATE_SELECT_N(num,n,array,mask,delay) generalise STATE_AWAIT and STATE_AWAIT_N to an array of events of length n.
Going from state to state is possible with:
  • GOTO(num) blocks execution for the current instant and sets the state for the next instant to be state num.
  • GOTO_NEXT blocks execution for the current instant and sets the state for the next instant to be the next state.
  • IMMEDIATE(num) forces execution to jump to state num which is immediately executed.
  • RETURN immediately terminates the automaton.
Finally, the following macros define some special variables:
  • SELF is the automaton.
  • SET_LOCAL(data) sets the local data of the automaton.
  • LOCAL is the local data of the automaton.
  • ARGS is the argument that is passed at creation to the automaton.
  • RETURN_CODE is the error code set by macros run during automaton execution.


3.7 Miscelaneous

Current Thread

The calling thread is returned by ft_thread_self().


Current Scheduler

The scheduler of the calling thread is returned by ft_thread_scheduler().


Pthread

The call ft_pthread(t) returns the native pthread which executes the fair thread t. This function gives direct access to the Pthreads implementation of FairThreads. In the rest of the paper, native thread and pthread will be considered as synonymous.


Exiting

The function ft_exit is equivalent to pthread_exit. The basic use of ft_exit is to terminate the pthread which is running the function main, without exiting from the whole process.




This page has been generated by
Scribe.
Last update Tue Jun 4 10:09:20 2002
ft_v1.0/doc/ft-4.html0100644000374300000260000002752607477072670011724 0ustar fb 4. API

4. API

Browsing

Home: Fair Threads in C

Previous chapter: API Overview
Next chapter: Examples


API

Constructors
Starting a Scheduler
Control of Threads
Broadcast of Events
Cooperation
Termination
Generating Events
Waiting Events
Selecting Events
Getting Generated Values
Link and Unlink
Current Thread and Scheduler
Exit
Locks
Pthreads
Macros for Automata


Chapters

1. Introduction
2. Rationale
3. API Overview
4. API
5. Examples
6. Related Work
7. Conclusion
8. Man Pages


Constructors

ft_scheduler_t ft_scheduler_create (void);
 
ft_thread_t    ft_thread_create    (ft_scheduler_t scheduler,
                                    void (*runnable)(void*),
                                    void (*cleanup)(void*),
                                    void *args);

ft_thread_t    ft_automaton_create (ft_scheduler_t,
                                    void (*automaton)(ft_thread_t),
                                    void (*cleanup)(void*),
                                    void *args);

ft_event_t     ft_event_create     (ft_scheduler_t scheduler);


Starting a Scheduler

int ft_scheduler_start  (ft_scheduler_t scheduler);


Control of Threads

int ft_scheduler_stop      (ft_thread_t thread);
int ft_scheduler_suspend   (ft_thread_t thread);
int ft_scheduler_resume    (ft_thread_t thread);


Broadcast of Events

int ft_scheduler_broadcast        (ft_event_t event);
int ft_scheduler_broadcast_value  (ft_event_t event,void *value);


Cooperation

int ft_thread_cooperate    (void);
int ft_thread_cooperate_n  (int num);


Termination

int ft_thread_join    (ft_thread_t thread);
int ft_thread_join_n  (ft_thread_t thread,int timeout);


Generating Events

int ft_thread_generate        (ft_event_t event);
int ft_thread_generate_value  (ft_event_t event,void *value);


Waiting Events

 
int ft_thread_await    (ft_event_t event);
int ft_thread_await_n  (ft_event_t event,int timeout);


Selecting Events

 
int ft_thread_select    (int len,ft_event_t *array,int *mask);
int ft_thread_select_n  (int len,ft_event_t *array,int *mask,int timeout);


Getting Generated Values

 
int ft_thread_get_value  (ft_event_t event,int num,void **result);


Link and Unlink

 
int ft_thread_link    (ft_scheduler_t scheduler);
int ft_thread_unlink  (void);


Current Thread and Scheduler

 
ft_thread_t     ft_thread_self       (void);
ft_scheduler_t  ft_thread_scheduler  (void);


Exit

void ft_exit  (void);


Locks

 
int ft_thread_mutex_lock    (pthread_mutex_t *mutex);
int ft_thread_mutex_unlock  (pthread_mutex_t *mutex);


Pthreads

 
pthread_t ft_pthread  (ft_thread_t thread);


Macros for Automata

 
AUTOMATON(name) 
DEFINE_AUTOMATON(name) 
BEGIN_AUTOMATON
END_AUTOMATON  

STATE(num)    
STATE_AWAIT(num,event) 
STATE_AWAIT_N(num,event,delay)
STATE_GET_VALUE(num,event,n,result) 
STATE_STAY(num,delay)               
STATE_JOIN(num,thread)              
STATE_JOIN_N(num,thread,delay)      
STATE_SELECT(num,n,array,mask)              
STATE_SELECT_N(num,n,array,mask,delay)

GOTO(num) 
GOTO_NEXT 
IMMEDIATE(num)
RETURN

SELF   
SET_LOCAL(data) 
LOCAL   
ARGS  
RETURN_CODE 



This page has been generated by
Scribe.
Last update Tue Jun 4 10:09:20 2002
ft_v1.0/doc/ft-5.html0100644000374300000260000002653207477072670011721 0ustar fb 5. Examples

5. Examples

Browsing

Home: Fair Threads in C

Previous chapter: API
Next chapter: Related Work


Examples

5.1 Hello World!
5.2 Blocking I/O
5.3 Producer/Consumer
5.4 Automata


Chapters

1. Introduction
2. Rationale
3. API Overview
4. API
5. Examples
6. Related Work
7. Conclusion
8. Man Pages


5.1 Hello World!

The following code is a complete example, made of two threads run in the same scheduler.

#include "fthread.h"
#include <stdio.h>

void h (void *id)
{
   while (1) {
      fprintf (stderr,"Hello ");
      ft_thread_cooperate ();
   }
}

void w (void *id)
{
   while (1) {
      fprintf (stderr,"World!\n");
      ft_thread_cooperate ();
   }
}

int main (void)
{
  ft_scheduler_t sched = ft_scheduler_create ();

  ft_thread_create (sched,h,NULL,NULL);
  ft_thread_create (sched,w,NULL,NULL);

  ft_scheduler_start (sched);

  ft_exit ();
  return 0;
}
The program outputs Hello World! cyclically. Note the call of ft_exit to prevent the program to terminate before executing the two threads. Execution of linked fair threads is round-robin and deterministic: messages Hello and World! are always printed in this order.

Here is the typical way to produce executable code:

gcc -D_REENTRANT -o test test.c -lfthread -lpthread 


5.2 Blocking I/O

The following function ft_thread_read implements a non-blocking read I/O, using the standard blocking read function. The calling thread first unlinks from the scheduler, then performs the read, and finally re-links to the scheduler:

ssize_t ft_thread_read (int fd,void *buf,size_t count)
{ 
   ft_scheduler_t sched = ft_thread_scheduler ();
   ssize_t res;
   
   ft_thread_unlink ();
   
   res = read (fd,buf,count);
   
   ft_thread_link (sched);
   return res;
}


5.3 Producer/Consumer

One implements a producer/consumer example. There are 2 files, in and out, and a pool of threads that take data from in, process them, and then put results in out. A scheduler and an event are associated to each file; the event is generated to indicate that a new value is produded in the associated file.

file in = NULL, out = NULL;
ft_scheduler_t in_sched, out_sched;
ft_event_t new_input, new_output;

Processing Values

In order to process a value v, the calling thread first unlinks from in_sched. After processing, it links to out_sched in order to put the result in out, and finally, it re-links to in_sched. The procedure for processing a value is the following (for simplicity, values are of type int):

void process_value (int v)
{
  ft_thread_unlink ();
  < process v >
  ft_thread_link (out_sched);
  put (v,&out);
  ft_thread_generate (new_output);
  ft_thread_unlink ();
  ft_thread_link (in_sched);
}
The function run by the processing threads is:
void process (void *args)
{
  while (1) {
    if (size(in) > 0) {
      process_value (get (&in));
    } else {
      ft_thread_await (new_input);
      if (size (in) == 0) ft_thread_cooperate ()
    }
  }
}
The event new_input is used to prevent polling when no value is available from in. However, to test it as present does not necessary implies that a value is available: it could have been consumed by another thread. Thus, a call to ft_thread_cooperate is needed to avoid an infinite loop during the same instant, if new_input is tested as present while no value is actually available.


Main Function

Two threads are added to the system: one for producing new values, and the other for consuming results. The main function is the following:

int main (void)
{
   int i;
   ft_thread_t thread_array [MAX_THREADS]

   in_sched  = ft_scheduler_create ();
   out_sched = ft_scheduler_create ();
   
   new_input  = ft_event_create (in_sched);
   new_output = ft_event_create (out_sched);     

   for (i=0; i<MAX_THREADS; i++) {
      thread_array[i] = ft_thread_create (in_sched,process,NULL,NULL);
   }
  
   ft_thread_create (in_sched,produce,NULL,NULL);
   ft_thread_create (out_sched,consume,NULL,NULL);

   ft_scheduler_start (in_sched);
   ft_scheduler_start (out_sched);  

   ft_exit ();
   return 0;
}



5.4 Automata

Preemption by an Event

Here is the example of a one-state automaton, named killer, that preempts a thread when an event is present. The thread and the event are accessible with the macro ARGS.

DEFINE_AUTOMATON (killer)
{
   void **args = ARGS;
   ft_event_t event   = args[0]
   ft_thread_t thread = args[1]
   
   BEGIN_AUTOMATON
     
     STATE_AWAIT (0,event)
     {
        ft_scheduler_stop (thread);
     }
  
   END_AUTOMATON
}
A fair thread is created by:
ft_thread_t a = ft_automaton_create (sched,killer,NULL,args);
The difference with a standard thread created by ft_thread_create is that no new pthread is actually created by ft_automaton_create. The automaton is simply run by the scheduler's pthread. Thus, no pthread context switch is needed and execution is more efficient.


Two Threads Run in Turn

The following automaton switches control between two threads, according to the presence of an event. The automaton switch_aut has three states. The first state resumes the first thread to run (initially, both threads are suspended). The switching event is awaited in the second state, and then the threads are switched. The third state is similar to the second, except that the threads are exchanged.

DEFINE_AUTOMATON (switch_aut)
{
   void **args = ARGS;
   
   ft_event_t   event   = args[0]
   ft_thread_t  thread1 = args[1]
   ft_thread_t  thread2 = args[2]
   
  BEGIN_AUTOMATON
     
     STATE (0)
     {
        ft_scheduler_resume (thread1);
     }
     STATE_AWAIT (1,event)
     {
        ft_scheduler_suspend (thread1);
        ft_scheduler_resume  (thread2);
        GOTO(2);
     }
     STATE_AWAIT (2,event)
     {
        ft_scheduler_suspend (thread2);
        ft_scheduler_resume  (thread1);
        GOTO(1);
     }
     
  END_AUTOMATON
}
If a standard thread were used instead of an automaton, one supplementary pthread would be needed to perform the same task.




This page has been generated by
Scribe.
Last update Tue Jun 4 10:09:20 2002
ft_v1.0/doc/ft-6.html0100644000374300000260000002001407477072670011707 0ustar fb 6. Related Work

6. Related Work

Browsing

Home: Fair Threads in C

Previous chapter: Examples
Next chapter: Conclusion


Related Work

Thread Libraries in C
Java Threads
Threads in Functional Languages
Reactive Approach
Chores and Filaments


Chapters

1. Introduction
2. Rationale
3. API Overview
4. API
5. Examples
6. Related Work
7. Conclusion
8. Man Pages


Thread Libraries in C

Several thread libraries exist for C. Among them, the Pthreads library [17] implements the POSIX standard for preemptive threads. LinuxThreads [4] is an implementation of Pthreads for Linux; it is based on kernel-level threads. Quick Threads [14] provides programmers with a minimal support for multithreading at user-space level. Basically, it implements context-switching in assembly code, and is thus a low-level solution to multithreading. Gnu Portable Threads [11] (GNU Pth) is a library of purely cooperative threads which has portability as main objective. The Next Generation POSIX Threading project [5] proposes to extend GNU Pth to the M:N model, with Linux SMP machines as target.


Java Threads

Java introduce threads at language level. Actually, threads are generally heavily used in Java, for example when graphics or networking is involved. No assumption is made on the way threads are scheduled (cooperative or preemptive scheduling) wich makes Java multithreaded systems difficult to program and to port [13]. This difficulty is pointed out by the suppression from the recent versions of the language of the threads primitives to gain fine control over threads [3]. A first version of FairThreads has been proposed in the context of the Java language [7] in order to simplify concurrent programming in Java.


Threads in Functional Languages

Threads are used in several ML-based languages such as CML [18]. CML is preemptively scheduled and threads communication is synchronous and based on channels. Threads are also introduced in CAML [2]; they are implemented by time-sharing on a single processor, and thus cannot benefit from multiprocessors machines. FairThreads has been recently introduced in the Bigloo [1] implementation of Scheme. The present version only supports linked threads, and special constructs are introduced to deal with non-blocking I/Os.


Reactive Approach

FairThreads actually comes out from the so-called reactive approach [6]. In this approach, one basically has instants and broadcast events. As opposite to synchronous languages [12] such as Esterel, the absence of an event during one instant cannot be decided before the end of this very instant. As a consequence, the reaction to the absence of one event is delayed to the next instant. This is a way to solve so-called "causality problems" which are raised with synchronous languages, and which are obstacles to modularity. The Reactive-C [8] language was the first proposal for reactive programming in C; in this respect, FairThreads can be considered as a descendant of it.


Chores and Filaments

Chores [10] and filaments [15] are small pieces of code that do not have private stack and are never preempted. Chores and filaments are designed for fine-grain parallelism programming on shared-memory machines. Chores and filaments are completely executed and cannot be suspended nor resumed. Generally, a pool of threads is devoted to execute them. Chores and chunk-based techniques are described in details in the context of the Java language in [9] and [13]. Automata in FairThreads are close to chores and filaments, but give programmers more freedom for direct coding of states-based algorithms. Automata are also related to mode automata [16] in which states capture the notion of a running mode in the context of the synchronous language Lustre.



This page has been generated by
Scribe.
Last update Tue Jun 4 10:09:20 2002
ft_v1.0/doc/ft-7.html0100644000374300000260000001271207477072670011716 0ustar fb 7. Conclusion

7. Conclusion

Browsing

Home: Fair Threads in C

Previous chapter: Related Work
Next chapter: Man Pages


Conclusion


Chapters

1. Introduction
2. Rationale
3. API Overview
4. API
5. Examples
6. Related Work
7. Conclusion
8. Man Pages


Multiprocessing

In FairThreads, users have control on the way threads are scheduled. Fair threads which are linked to a scheduler are scheduled in a cooperative way by it. When a fair thread unlinks from a scheduler, it becomes an autonomous native thread which can be run in real parallelism, on a distinct processor. An important point is that FairThreads provides users with programming primitives allowing threads to dynamically link to schedulers and to dynamically unlink from them.


Precise Semantics

Linked threads have a precise and clear semantics (which can be formally given). The point is that systems exclusively made of threads linked to one unique scheduler are completely deterministic.


Simplicity

FairThreads offers a very simple framework for concurrent and parallel programming. Simple cooperative systems can be coded in a simple way, without the need of locks to protect data. Instants give automatic synchronizations that can also simplify programming in certain situations.


Compatibility with Pthreads

FairThreads is fully compatible with the standard Pthreads library. Indeed, unlinked fair threads are actually just pthreads. In this respect, FairThreads is an extension of Pthreads, which allows users to define cooperative contexts with a clear and simple semantics, in which threads execute at the same pace and events are instantaneously broadcast.


Automata

Auxiliary tasks can be implemented using automata instead of standard fair threads. Implementation of an automaton is lightweight and does not require a dedicated native thread. Automata are useful for short-lived small tasks or when a large number of tasks is needed. Automata are an alternative to standard techniques such as "chunks" or "chores", sometimes used in thread-based programming.


Implementation

A first implementation of FairThreads is available (under the GNU General Public License as a library called fthread [6] which must be used with the standard Pthreads library.



This page has been generated by
Scribe.
Last update Tue Jun 4 10:09:20 2002
ft_v1.0/doc/ft-8.html0100644000374300000260000011357307477072670011726 0ustar fb 8. Man Pages

8. Man Pages

Browsing

Home: Fair Threads in C

Previous chapter: Conclusion
Next chapter:


Man Pages

8.1 ft_scheduler_create
8.2 ft_thread_create
8.3 ft_event_create
8.4 ft_scheduler_stop
8.5 ft_scheduler_broadcast
8.6 ft_thread_cooperate
8.7 ft_thread_join
8.8 ft_thread_generate
8.9 ft_thread_get_value
8.10 ft_thread_link
8.11 ft_thread_self
8.12 ft_thread_mutex_lock
8.13 ft_exit
8.14 ft_pthread
8.15 ft_automaton_create


Chapters

1. Introduction
2. Rationale
3. API Overview
4. API
5. Examples
6. Related Work
7. Conclusion
8. Man Pages


8.1 ft_scheduler_create

SYNOPSIS

#include <fthread.h>

ft_scheduler_t ft_scheduler_create (void);

int ft_scheduler_start (ft_scheduler_t sched);


DESCRIPTION

ft_scheduler_create returns a new scheduler that will run the threads created in it, using ft_thread_create. The new scheduler sched starts running when the function ft_scheduler_start is called.


RETURN VALUES

On success ft_scheduler_create returns the new scheduler; NULL is returned otherwise. On success the value 0 is returned by ft_scheduler_start and a non-zero error code is returned otherwise.


ERRORS

NULL
The scheduler cannot be created.
BADCREATE
The scheduler sched is not correctly created when started.


SEE ALSO

ft_thread_create (3).



8.2 ft_thread_create

SYNOPSIS

#include <fthread.h>

ft_thread_t ft_thread_create (ft_scheduler_t sched,
                              void (*runnable)(void*),
                              void (*cleanup)(void*),                     
                              void *args);


DESCRIPTION

ft_thread_create returns a new thread of control and links it to the scheduler sched. While linked in sched, the new thread will execute concurrently with the other threads linked in it. Actual starting of the new thread is asynchronous with the creation. The new thread applies the function runnable passing it args as first argument. The new thread terminates when it executes ft_exit or when it returns from the runnable function.

When stopped (by ft_scheduler_stop), the new thread applies the function cleanup, if it is not NULL, passing it args as first argument.

A pthread is created with each fair thread. This pthread is initially attached. It can be detached using ft_pthread and pthread_detach.


RETURN VALUES

On success, ft_thread_create returns a new thread; NULL is returned otherwise.


ERRORS

NULL
The thread cannot be created, or the scheduler sched is not correctly created.


SEE ALSO

ft_exit (3), ft_scheduler_create (3), ft_scheduler_stop (3), ft_pthread (3).



8.3 ft_event_create

SYNOPSIS

#include <fthread.h>

ft_event_t ft_event_create (ft_scheduler_t sched);


DESCRIPTION

ft_event_create returns a new event which is created in the scheduler sched. The event can be generated by ft_event_generate or ft_scheduler_broadcast, and it can awaited by ft_event_await.


RETURN VALUES

On success, the new event is returned and set to absent; NULL is returned otherwise.


ERRORS

NULL
The event cannot be created or the scheduler sched is not correctly created.


SEE ALSO

ft_event_generate (3), ft_scheduler_broadcast (3), ft_event_await (3).



8.4 ft_scheduler_stop

SYNOPSIS

#include <fthread.h>

int ft_scheduler_stop    (ft_thread_t th);

int ft_scheduler_suspend (ft_thread_t th);

int ft_scheduler_resume  (ft_thread_t th);


DESCRIPTION

ft_scheduler_stop asks the scheduler running the thread th to force termination of it. Nothing special happens if the thread is already terminated. Otherwise, at the begining of the next instant, th executes the function cleanup if it exists, or otherwise terminates immediately.

ft_scheduler_suspend asks the scheduler running the thread th to suspend execution of it. The suspension will become actual at the beginning of the next instant of the scheduler.

ft_scheduler_resume asks the scheduler running the thread th to resume execution of it. The resume will become actual at the beginning of the next instant of the scheduler. Suspension has higher priority than resume: if a thread is suspended and resumed during the same instant, then the thread will be suspended. A suspended thread which is stopped is first resumed.


RETURN VALUES

On success, the value 0 is returned. On error, a non-zero error code is returned.


ERRORS

BADCREATE
The thread th is not correctly created.
BADLINK
The thread th is unlinked.
BADMEM
Not enough memory (the order cannot be stored by the scheduler).


SEE ALSO

ft_thread_create (3), ft_scheduler_create (3).



8.5 ft_scheduler_broadcast

SYNOPSIS

#include <fthread.h>

int ft_scheduler_broadcast       (ft_event_t evt);

int ft_scheduler_broadcast_value (ft_event_t evt,void *val);


DESCRIPTION

ft_scheduler_broadcast asks the scheduler of the event evt to broadcast it. The event will be generated during the next instant of the scheduler. The value val is associated to evt when the function ft_scheduler_broadcast_value is used.


RETURN VALUES

On success, the value 0 is returned. On error, a non-zero error code is returned.


ERRORS

BADCREATE
The event evt is not correctly created.
BADMEM
Not enough memory (the scheduler cannot store the broadcast order).


SEE ALSO

ft_event_create (3).



8.6 ft_thread_cooperate

SYNOPSIS

#include <fthread.h>

int ft_thread_cooperate   (void);

int ft_thread_cooperate_n (int n);


DESCRIPTION

ft_thread_cooperate makes the calling thread cooperate by returning the control to the scheduler in which it is running. The call ft_thread_cooperate_n (k) is equivalent to for (i=0;i<k;i++) ft_thread_cooperate ().


RETURN VALUES

On success, the value 0 is returned. On error, a non-zero error code is returned.


ERRORS

BADLINK
The calling thread is unlinked.



8.7 ft_thread_join

SYNOPSIS

#include <fthread.h>

int ft_thread_join   (ft_thread_t th);

int ft_thread_join_n (ft_thread_t th,int n);


DESCRIPTION

ft_thread_join suspends the execution of the calling thread until the thread th terminates (either by reaching the end of the function it run, or by executing ft_exit) or is stopped (by ft_scheduler_stop). If th is already terminated, the call immediately terminates. ft_thread_join_n (th,i) waits for at most i instants for termination of th.


RETURN VALUES

On success, the value 0 is returned. On error, a non-zero error code is returned.


ERRORS

BADCREATE
The thread th is not correctly created.
BADLINK
The calling thread is unlinked.
TIMEOUT
The timeout is reached before the thread is joined.


SEE ALSO

ft_thread_create (3), ft_exit (3), ft_scheduler_stop (3).



8.8 ft_thread_generate

SYNOPSIS

#include <fthread.h>

int ft_thread_generate       (ft_event_t evt);

int ft_thread_generate_value (ft_event_t evt,void *val);

int ft_thread_await          (ft_event_t evt);

int ft_thread_await_n        (ft_event_t evt,int n);

int ft_thread_select         (int len,ft_event_t *array,int *mask);

int ft_thread_select_n       (int len,ft_event_t *array,int *mask,int timeout);


DESCRIPTION

ft_thread_generate generates the event evt for the current instant of the scheduler in which the calling thread is running. The event is thus present for this instant; it will be automatically reset to absent at the begining of the next instant. The value val is associated to evt when ft_thread_generate_value is used.

ft_thread_await suspends the calling thread until evt becomes generated in the scheduler in which it is running. The waiting takes as many instants as the generation of evt takes. ft_thread_await_n (evt,k) is similar to ft_thread_await (evt) except that the waiting of evt lasts at most k instants.

ft_thread_select suspends the calling thread until one element of array becomes generated in the scheduler in which the thread is running; array should be of length k. On resumption, mask which is an array of k integers, is set accordingly: mask[i] is 1 if array[i] was generated; mask[i] is 0, otherwise. ft_thread_select_n (k,array,mask,p) is similar to ft_thread_select (k,array,mask) except that the waiting lasts at most p instants.


RETURN VALUES

On success the value 0 is returned and a non-zero error code is returned on error.


ERRORS

BADCREATE
The exist an event (either evt or an element of array) which is not correctly created.
BADLINK
Either the calling thread is unlinked, or the scheduler of the calling thread and the one of a considered event (evt or an element of array) are different.
BADMEM
Not enough memory (can only occur with ft_thread_generate_value).
TIMEOUT
The timeout is reached.


SEE ALSO

ft_event_create (3), ft_thread_get_value (3).



8.9 ft_thread_get_value

SYNOPSIS

#include <fthread.h>

int ft_thread_get_value (ft_event_t evt,int n,void **result);


DESCRIPTION

ft_thread_get_value returns the nth value associated during the current instant to the event evt through calls of ft_event_generate_value or ft_scheduler_broadcast_value. If such a value exists, ft_thread_get_value sets result with a reference to it and terminates immediately (that is, during the current instant). Otherwise, it terminates at the next instant (returning NEXT) and result is then set to NULL.


RETURN VALUES

On success, the value 0 is returned (during the current instant). Otherwise, a non-zero error code is returned.


ERRORS

BADCREATE
The event evt is not correctly created.
BADLINK
Either the calling thread is unlinked, or the scheduler of the calling thread and the one of evt are different.
NEXT
Less than n values where actually associated to generations of evt during the previous instant.


SEE ALSO

ft_thread_generate_value (3), ft_scheduler_broadcast_value (3).



8.10 ft_thread_link

SYNOPSIS

#include <fthread.h>

int ft_thread_unlink (void);

int ft_thread_link   (ft_scheduler_t sched);


DESCRIPTION

ft_thread_unlink unlinks the calling thread from the scheduler which is running it. Execution of the thread suspends until the begining of the next instant of the scheduler. At that point, the thread turns into a standard thread, not linked to any scheduler, and it resumes execution autonomously. Initialy, a fair thread is automatically linked to the scheduler in which it is created (by ft_thread_create). ft_thread_link links the calling thread to the scheduler sched. The thread must be unlinked. Execution suspends until sched gives the control to the thread; then, the thread resumes execution, being scheduled by sched.


RETURN VALUES

On success, the value 0 is returned. On error, a non-zero error code is returned.


ERRORS

BADCREATE
The scheduler sched is not correctly created.
BADLINK
The calling thread is already linked while running ft_thread_link, or it is unlinked while running ft_thread_unlink.
BADMEM
Not enough memory (the scheduler cannot store the link/unlink order).


SEE ALSO

ft_thread_create (3).



8.11 ft_thread_self

SYNOPSIS

#include <fthread.h>

ft_thread_t    ft_thread_self      (void);

ft_scheduler_t ft_thread_scheduler (void);


DESCRIPTION

ft_thread_self returns the calling thread. ft_thread_scheduler returns the scheduler of the calling thread.


ERRORS

The value NULL is returned by ft_thread_self when the calling thread is not correctly created, or by ft_thread_scheduler when the calling thread is not correctly created or is unlinked.



8.12 ft_thread_mutex_lock

SYNOPSIS

#include <fthread.h>

int ft_thread_mutex_lock   (pthread_mutex_t *mutex);

int ft_thread_mutex_unlock (pthread_mutex_t *mutex);


DESCRIPTION

For unlinked threads, ft_thread_mutex_lock is like pthread_mutex_lock and ft_thread_mutex_unlock is like pthread_mutex_unlock.

For linked threads, ft_thread_mutex_lock suspends the calling thread until mutex can be locked. Thus, while mutex is unavailable, other threads in the scheduler can continue to run (this would not be the case if pthread_mutex_lock where used instead of ft_thread_mutex_lock). All locks owned by a thread are automatically released when it terminates or when it is stopped.


RETURN VALUES

On success ft_thread_mutex_lock and ft_thread_mutex_unlock both return the value 0. On error, a non-zero error code is returned.


ERRORS

Errors returned are the ones returned by pthread_mutex_lock and pthread_mutex_unlock.


SEE ALSO

ft_thread_link (3), ft_thread_unlink (3).



8.13 ft_exit

SYNOPSIS

#include <fthread.h>

void ft_exit (void);


DESCRIPTION

ft_exit forces the calling thread to terminate.


RETURN VALUES

The function ft_exit never returns.



8.14 ft_pthread

SYNOPSIS

#include <fthread.h>

pthread_t ft_pthread (ft_thread_t thread);


DESCRIPTION

The function ft_pthread returns the pthread on which the fair thread thread is built.



8.15 ft_automaton_create

SYNOPSIS

#include <fthread.h>

ft_thread_t ft_automaton_create (ft_scheduler_t sched,
                                 void (*automaton)(ft_thread_t),
                                 void (*cleanup)(void*),                     
                                 void *args);

AUTOMATON(name) 
DEFINE_AUTOMATON(name) 
BEGIN_AUTOMATON
END_AUTOMATON  

STATE(num)    
STATE_AWAIT(num,event) 
STATE_AWAIT_N(num,event,delay)
STATE_GET_VALUE(num,event,n,result) 
STATE_STAY(num,delay)               
STATE_JOIN(num,thread)              
STATE_JOIN_N(num,thread,delay)
STATE_SELECT(num,n,array,mask)              
STATE_SELECT_N(num,n,array,mask,delay)

GOTO(num) 
GOTO_NEXT 
IMMEDIATE(num)
RETURN

SELF   
SET_LOCAL(data) 
LOCAL   
ARGS  
RETURN_CODE 


DESCRIPTION

ft_automaton_create is very similar to ft_thread_create except that a new automaton is returned. The automaton does not have its own pthread to execute, but it is run by the one of the scheduler. The automaton applies the function automaton. Argument args can be accessed in the automaton definition with the macro ARGS.


  • AUTOMATON(name) declares the automaton name.
  • DEFINE_AUTOMATON(name) starts definion of the automaton name.
  • BEGIN_AUTOMATON starts the state list.
  • END_AUTOMATON ends the state list.
  • STATE(num) starts state num description. States must be numbered consecutively, starting from 0. State 0 is the initial state.
  • STATE_AWAIT(num,event) awaits event. It is the counterpart of ft_thread_await for automata. Execution stays in this state until event is generated.
  • STATE_AWAIT_N(num,event,n) awaits event during at most n instant. It is the counterpart of ft_thread_await_n.
  • STATE_GET_VALUE(num,event,n,result) is used to get the nth value generated with event. It is the counterpart of ft_thread_get_value.
  • STATE_JOIN(num,thread) is used to join thread. It is the counterpart of ft_thread_join.
  • STATE_JOIN_N(num,thread,n) is an attempt to join thread during at most n instants. It is the counterpart of ft_thread_join_n.
  • STATE_STAY(num,n) let the automaton stay for n instants in the state.
  • STATE_SELECT(num,k,array,mask) awaits elements of array which is an array of events of length k. It is the counterpart of ft_thread_select for automata. Execution stays in this state until at least one element of array is generated; the presence of events is recorded in mask which is an array of integers of length k.
  • STATE_SELECT_N(num,k,array,mask,n) awaits elements of array during at most n instant. It is the counterpart of ft_thread_select_n.
  • GOTO(num) blocks execution for the current instant and sets the state to be executed at the next instant to be state num.
  • GOTO_NEXT blocks execution for the current instant and sets the state for the next instant to be the next state.
  • IMMEDIATE(num) forces execution to jump to state n which is immediately (that is, during the same instant) executed.
  • RETURN forces immediate termination of the automaton.
  • SELF is the automaton. It is of type ft_thread_t.
  • LOCAL is the local data of the automaton. The local data is of type void*.
  • SET_LOCAL(data) sets the local data of the automaton.
  • ARGS is the argument that is passed at creation to the automaton. It is of type void*.
  • RETURN_CODE is the error code set by macros run by the automaton. As usual, 0 means success.
Note that there is no counterpart of ft_thread_link and ft_thread_unlink for automata, as an automaton always remains linked to the scheduler in which it was created.



RETURN VALUES

On success, ft_automaton_create returns a new thread; NULL is returned otherwise.

When an error is encountered during execution of a macro, RETURN_CODE is set accordingly, with one of the error values BADMEM, TIMEOUT, NEXT, BADLINK, or BADCREATE.


ERRORS

NULL
The automaton cannot be created, or the scheduler sched is not correctly created.


EXAMPLE

The following automaton switches control between two threads, according to the presence of an event.

DEFINE_AUTOMATON(switch_aut)
{
   void **args = ARGS;
   
   ft_event_t   event   = args[0]
   ft_thread_t  thread1 = args[1]
   ft_thread_t  thread2 = args[2]
   
  BEGIN_AUTOMATON
     
     STATE(0)
     {
        ft_scheduler_resume (thread1);
     }
     STATE_AWAIT (1,event)
     {
        ft_scheduler_suspend (thread1);
        ft_scheduler_resume  (thread2);
        GOTO(2);
     }
     STATE_AWAIT (2,event)
     {
        ft_scheduler_suspend (thread2);
        ft_scheduler_resume  (thread1);
        GOTO(1);
     }
     
  END_AUTOMATON
}


SEE ALSO

ft_thread_create (3), ft_thread_await (3), ft_thread_get_value (3), ft_thread_join (3).




This page has been generated by
Scribe.
Last update Tue Jun 4 10:09:20 2002
ft_v1.0/doc/ft.html0100644000374300000260000001447407477072670011561 0ustar fb scribe-document

Fair Threads in C

F. Boussinot
EMP-CMA/INRIA - MIMOSA Project
2004 route des Lucioles - BP 93
F-06902 Sophia Antipolis, Cedex
Frederic.Boussinot@sophia.inria.fr

Chapters

1. Introduction
2. Rationale
3. API Overview
4. API
5. Examples
6. Related Work
7. Conclusion
8. Man Pages


Abstract

FairThreads offers a very simple framework for concurrent and parallel programming. Basically, it defines schedulers which are synchronization servers, to which threads can dynamically link or unlink. All threads linked to the same scheduler are executed in a cooperative way, at the same pace, and they can synchronize and communicate using broadcast events. Threads which are not linked to any scheduler are executed by the OS in a preemptive way, at their own pace. FairThreads offers programming constructs for linking and unlinking threads. FairThreads is fully compatible with the standard Pthreads library and has a precise and clear semantics for its cooperative part; in particular, systems exclusively made of threads linked to one unique scheduler are actually completely deterministic. Special threads, called automata, are provided for short-lived small tasks or when a large number of tasks is needed. Automata do not need the full power of a native thread to execute and thus consume less resources.


[1] Bigloo Web Site.

[2] CAML Web Site.

[3] Java Web Site.

[4] LinuxThreads Web Site.

[5] Next Generation POSIX Threading Web Site.

[6] Reactive Programming Web Site.

[7] Boussinot, F. -- Java Fair Threads -- Inria research report, RR-4139, 2001.

[8] Boussinot, F. -- Reactive C: An Extension of C to Program Reactive Systems -- Software-Practice and Experience, 21(4), 1991.

[9] Christopher, Thomas W. and Thiruvathukal, George K. -- High Performance Java Platform Computing: Multithreaded and Networked Programming -- Sun Microsystems Press Java Series, Prentice Hall, 2001.

[10] Eager, Derek L. and Zahorjan, John -- Chores: Enhanced run-time support for shared memory parallel computing -- ACM Transaction on Computer Systems, 11(1), 1993.

[11] Engelschall, Ralf S. -- Portable Multithreading -- Proc. USENIX Annual Technical Conference, San Diego, California, 2000.

[12] Halbwachs, Nicolas -- Synchronous Programming of Reactive Systems -- Kluwer Academic Publishers, New York, 1993.

[13] Hollub, A. -- Taming Java Threads -- Apress, 2000.

[14] Keppel, D. -- Tools and Techniques for Building Fast Portable Threads Packages -- Technical Report UWCSE 93-05-06, University of Washington, 1993.

[15] Lowenthal, David K and Freech, Vincent W. and Andrews, Gregory R. -- Efficient Support for Fine-Grain Parallelism on Shared-Memory Machines -- TR 96-1, University of Arizona, 1996.

[16] Maraninchi, F. and Remond, Y. -- Running-Modes of Real-Time Systems: A Case-Study with Mode-Automata -- Proc. 12th Euromicro Conference on Real-Time Systems, Stockholm, Sweden, 2000.

[17] Nichols, B. and Buttlar, D. and Proulx Farrell J. -- Pthreads Programming -- O'Reilly, 1996.

[18] Reppy, John H. -- Concurrent Programming in ML -- Cambridge University Press, 1999.


This page has been generated by Scribe.
Last update Tue Jun 4 10:09:20 2002
ft_v1.0/tests/0040755000374300000260000000000007477072670010650 5ustar fbft_v1.0/tests/aut1.c0100644000374300000260000000323107477072670011662 0ustar fb#include "fthread.h" #include /* simultaneous events */ ft_event_t event1,event2; DEFINE_AUTOMATON (autom) { BEGIN_AUTOMATON STATE_AWAIT (0,event1); STATE_AWAIT (1,event2) { fprintf (stdout, "both events are received! "); } END_AUTOMATON } /*********************************/ void generator (void *args) { ft_thread_cooperate_n (4); fprintf (stdout, "event1 generated! "); ft_thread_generate (event1); ft_thread_cooperate_n (4); fprintf (stdout, "event1 and event2 are generated! "); ft_thread_generate (event1); ft_thread_generate (event2); ft_thread_cooperate (); fprintf (stdout, "exit\n"); exit (0); } void traceInstants (void *args) { int i = 0; for (i=0;i<10;i++) { fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i); ft_thread_cooperate (); } fprintf (stdout, "exit!\n"); exit (0); } int main () { ft_scheduler_t sched = ft_scheduler_create (); event1 = ft_event_create (sched); event2 = ft_event_create (sched); ft_thread_create (sched,traceInstants,NULL,NULL); if (NULL == ft_automaton_create (sched,autom,NULL,NULL)) { fprintf (stdout, "cannot create automaton!!!\n"); } ft_thread_create (sched,generator,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: >>>>>>>>>>> instant 1: >>>>>>>>>>> instant 2: >>>>>>>>>>> instant 3: >>>>>>>>>>> instant 4: event1 generated! >>>>>>>>>>> instant 5: >>>>>>>>>>> instant 6: >>>>>>>>>>> instant 7: >>>>>>>>>>> instant 8: event1 and event2 are generated! both events are received! >>>>>>>>>>> instant 9: exit end result */ ft_v1.0/tests/aut10.c0100644000374300000260000000426307477072670011750 0ustar fb#include "fthread.h" #include #include #include /* preemption using an auxiliary automaton */ /*************************************/ ft_scheduler_t sched; /*************************************/ DEFINE_AUTOMATON(killer) { void **args = ARGS; ft_event_t event = (ft_event_t)(args[0]); ft_thread_t thread = (ft_thread_t)(args[1]); BEGIN_AUTOMATON STATE_AWAIT(0,event) ft_scheduler_stop (thread); fprintf (stdout, "stop thread!\n"); END_AUTOMATON } /*************************************/ void printer (void *args) { while (1) { fprintf (stdout, "*"); ft_thread_cooperate (); } } void until (void *args) { ft_event_t event = (ft_event_t) args; ft_thread_t pr = ft_thread_create (sched,printer,NULL,NULL); void **v = malloc (2); v[0] = event; v[1] = pr; ft_automaton_create (sched,killer,NULL,v); } /*************************************/ void traceInstants (void *args) { int i = 0; for (i=0;i<20;i++) { fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i); ft_thread_cooperate (); } fprintf (stdout, "exit!\n"); exit (0); } void generator (void *args) { ft_thread_cooperate_n (10); ft_thread_generate ((ft_event_t)args); fprintf (stdout, "event generated! "); } int main(void) { ft_event_t event; sched = ft_scheduler_create (); event = ft_event_create (sched); ft_thread_create (sched,traceInstants,NULL,NULL); ft_thread_create (sched,generator,NULL,event); ft_thread_create (sched,until,NULL,event); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: >>>>>>>>>>> instant 1: * >>>>>>>>>>> instant 2: * >>>>>>>>>>> instant 3: * >>>>>>>>>>> instant 4: * >>>>>>>>>>> instant 5: * >>>>>>>>>>> instant 6: * >>>>>>>>>>> instant 7: * >>>>>>>>>>> instant 8: * >>>>>>>>>>> instant 9: * >>>>>>>>>>> instant 10: event generated! *stop thread! >>>>>>>>>>> instant 11: >>>>>>>>>>> instant 12: >>>>>>>>>>> instant 13: >>>>>>>>>>> instant 14: >>>>>>>>>>> instant 15: >>>>>>>>>>> instant 16: >>>>>>>>>>> instant 17: >>>>>>>>>>> instant 18: >>>>>>>>>>> instant 19: exit! end result */ ft_v1.0/tests/aut11.c0100644000374300000260000000335307477072670011750 0ustar fb#include "fthread.h" #include #include #include /* JOIN */ /*************************************/ DEFINE_AUTOMATON(joiner) { BEGIN_AUTOMATON STATE_JOIN(0,(ft_thread_t)ARGS) fprintf (stdout, "thread joined!\n"); END_AUTOMATON } /*************************************/ void printer (void *args) { int i; for (i=0;i<10;i++) { fprintf (stdout, "*"); ft_thread_cooperate (); } fprintf (stdout, "end of print! "); } /*************************************/ void traceInstants (void *args) { int i = 0; for (i=0;i<20;i++) { fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i); ft_thread_cooperate (); } fprintf (stdout, "exit!\n"); exit (0); } int main(void) { ft_scheduler_t sched = ft_scheduler_create (); ft_thread_t pr,a1,a2,a3; ft_thread_create (sched,traceInstants,NULL,NULL); pr = ft_thread_create (sched,printer,NULL,NULL); a1 = ft_automaton_create (sched,joiner,NULL,pr); a2 = ft_automaton_create (sched,joiner,NULL,a1); a3 = ft_automaton_create (sched,joiner,NULL,a2); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: * >>>>>>>>>>> instant 1: * >>>>>>>>>>> instant 2: * >>>>>>>>>>> instant 3: * >>>>>>>>>>> instant 4: * >>>>>>>>>>> instant 5: * >>>>>>>>>>> instant 6: * >>>>>>>>>>> instant 7: * >>>>>>>>>>> instant 8: * >>>>>>>>>>> instant 9: * >>>>>>>>>>> instant 10: end of print! thread joined! thread joined! thread joined! >>>>>>>>>>> instant 11: >>>>>>>>>>> instant 12: >>>>>>>>>>> instant 13: >>>>>>>>>>> instant 14: >>>>>>>>>>> instant 15: >>>>>>>>>>> instant 16: >>>>>>>>>>> instant 17: >>>>>>>>>>> instant 18: >>>>>>>>>>> instant 19: exit! end result */ ft_v1.0/tests/aut12.c0100644000374300000260000000263507477072670011753 0ustar fb#include "fthread.h" #include #include #include /* JOIN_N */ /*************************************/ DEFINE_AUTOMATON(joiner) { BEGIN_AUTOMATON STATE_JOIN_N(0,(ft_thread_t)ARGS,10) if (RETURN_CODE == ETIMEOUT) fprintf (stdout, "timeout!\n"); else fprintf (stdout, "thread joined!\n"); STATE(1) fprintf (stdout, "exit!\n"); exit(0); END_AUTOMATON } /*************************************/ void printer (void *args) { int i; for (i=0;i<30;i++) { fprintf (stdout, "*"); ft_thread_cooperate (); } } /*************************************/ void traceInstants (void *args) { int i = 0; for (i=0;i<20;i++) { fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i); ft_thread_cooperate (); } } int main(void) { ft_scheduler_t sched = ft_scheduler_create (); ft_thread_t pr; ft_thread_create (sched,traceInstants,NULL,NULL); pr = ft_thread_create (sched,printer,NULL,NULL); ft_automaton_create (sched,joiner,NULL,pr); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: * >>>>>>>>>>> instant 1: * >>>>>>>>>>> instant 2: * >>>>>>>>>>> instant 3: * >>>>>>>>>>> instant 4: * >>>>>>>>>>> instant 5: * >>>>>>>>>>> instant 6: * >>>>>>>>>>> instant 7: * >>>>>>>>>>> instant 8: * >>>>>>>>>>> instant 9: * >>>>>>>>>>> instant 10: *timeout! exit! end result */ ft_v1.0/tests/aut13.c0100644000374300000260000000623607477072670011755 0ustar fb#include "fthread.h" #include #include #include /* preemption using two auxiliary automata */ /*************************************/ DEFINE_AUTOMATON(joiner) { void **args = ARGS; ft_thread_t to_join = (ft_thread_t)(args[0]); ft_thread_t to_stop = (ft_thread_t)(args[1]); BEGIN_AUTOMATON STATE_JOIN(0,to_join) { ft_scheduler_stop (to_stop); fprintf (stdout, "joiner terminates! "); } END_AUTOMATON } void awaiter_cleanup (void *args) { fprintf (stdout, "awaiter is killed! "); } DEFINE_AUTOMATON(awaiter) { void **args = ARGS; ft_event_t to_await = (ft_event_t) (args[0]); ft_thread_t to_stop = (ft_thread_t)(args[1]); BEGIN_AUTOMATON STATE_AWAIT(0,to_await) { ft_scheduler_stop (to_stop); fprintf (stdout, "awaiter terminates! "); } END_AUTOMATON } DEFINE_AUTOMATON(until) { void **args = ARGS; ft_scheduler_t sched = (ft_scheduler_t)(args[0]); ft_event_t event = (ft_event_t) (args[1]); ft_executable_t run = (ft_executable_t) (args[2]); BEGIN_AUTOMATON STATE(0) { ft_thread_t controlled,awaiter_aut; void **v1 = malloc (2), **v2 = malloc (2); controlled = ft_thread_create (sched,run,NULL,NULL); v1[0] = event; v1[1] = controlled; awaiter_aut = ft_automaton_create (sched,awaiter,awaiter_cleanup,v1); v2[0] = controlled; v2[1] = awaiter_aut; ft_automaton_create (sched,joiner,NULL,v2); } END_AUTOMATON } /*************************************/ void printer (void *args) { int i; for (i=0;i<5;i++) { fprintf (stdout, "*"); ft_thread_cooperate (); } fprintf (stdout, "printer terminates! "); } /*************************************/ void traceInstants (void *args) { int i = 0; for (i=0;i<20;i++) { fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i); ft_thread_cooperate (); } fprintf (stdout, "exit!\n"); exit (0); } void generator (void *args) { ft_thread_cooperate_n (11); ft_thread_generate ((ft_event_t)args); fprintf (stdout, "event generated! "); } int main(void) { void **v = malloc (3); ft_scheduler_t sched = ft_scheduler_create (); ft_event_t event = ft_event_create (sched); ft_thread_create (sched,traceInstants,NULL,NULL); ft_thread_create (sched,generator,NULL,event); v[0] = sched; v[1] = event; v[2] = printer; ft_automaton_create (sched,until,NULL,v); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: >>>>>>>>>>> instant 1: * >>>>>>>>>>> instant 2: * >>>>>>>>>>> instant 3: * >>>>>>>>>>> instant 4: * >>>>>>>>>>> instant 5: * >>>>>>>>>>> instant 6: printer terminates! joiner terminates! >>>>>>>>>>> instant 7: awaiter is killed! >>>>>>>>>>> instant 8: >>>>>>>>>>> instant 9: >>>>>>>>>>> instant 10: >>>>>>>>>>> instant 11: event generated! >>>>>>>>>>> instant 12: >>>>>>>>>>> instant 13: >>>>>>>>>>> instant 14: >>>>>>>>>>> instant 15: >>>>>>>>>>> instant 16: >>>>>>>>>>> instant 17: >>>>>>>>>>> instant 18: >>>>>>>>>>> instant 19: exit! end result */ ft_v1.0/tests/aut14.c0100644000374300000260000000334707477072670011756 0ustar fb#include "fthread.h" #include #include #include /* */ ft_event_t event; /*************************************/ DEFINE_AUTOMATON(autom_behav) { BEGIN_AUTOMATON STATE_AWAIT_N(0,(ft_event_t)ARGS,15) { fprintf (stdout, "exit!\n"); exit(0); } END_AUTOMATON } /*************************************/ void controler (void *args) { ft_thread_t autom = (ft_thread_t)args; ft_thread_cooperate_n (3); fprintf (stdout, "suspend autom! "); ft_scheduler_suspend (autom); ft_thread_cooperate_n (3); fprintf (stdout, "generate event! "); ft_thread_generate (event); ft_thread_cooperate_n (3); fprintf (stdout, "resume autom! "); ft_scheduler_resume (autom); } /*************************************/ void traceInstants (void *args) { int i = 0; for (i=0;i<20;i++) { fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i); ft_thread_cooperate (); } } int main(void) { ft_thread_t autom; ft_scheduler_t sched = ft_scheduler_create (); event = ft_event_create (sched); autom = ft_automaton_create (sched,autom_behav,NULL,event); ft_thread_create (sched,traceInstants,NULL,NULL); ft_thread_create (sched,controler,NULL,autom); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: >>>>>>>>>>> instant 1: >>>>>>>>>>> instant 2: >>>>>>>>>>> instant 3: suspend autom! >>>>>>>>>>> instant 4: >>>>>>>>>>> instant 5: >>>>>>>>>>> instant 6: generate event! >>>>>>>>>>> instant 7: >>>>>>>>>>> instant 8: >>>>>>>>>>> instant 9: resume autom! >>>>>>>>>>> instant 10: >>>>>>>>>>> instant 11: >>>>>>>>>>> instant 12: >>>>>>>>>>> instant 13: >>>>>>>>>>> instant 14: exit! end result */ ft_v1.0/tests/aut15.c0100644000374300000260000000330107477072670011745 0ustar fb#include "fthread.h" #include #include #include /* */ ft_event_t event; /*************************************/ DEFINE_AUTOMATON(autom_behav) { BEGIN_AUTOMATON STATE_AWAIT_N(0,(ft_event_t)ARGS,10) fprintf (stdout, "exit!\n"); exit(0); END_AUTOMATON } /*************************************/ void controler (void *args) { ft_thread_t autom = (ft_thread_t)args; ft_thread_cooperate_n (3); fprintf (stdout, "suspend autom! "); ft_scheduler_suspend (autom); ft_thread_cooperate_n (15); fprintf (stdout, "resume autom! "); ft_scheduler_resume (autom); } /*************************************/ void traceInstants (void *args) { int i = 0; for (i=0;i<20;i++) { fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i); ft_thread_cooperate (); } } int main(void) { ft_thread_t autom; ft_scheduler_t sched = ft_scheduler_create (); event = ft_event_create (sched); autom = ft_automaton_create (sched,autom_behav,NULL,event); ft_thread_create (sched,traceInstants,NULL,NULL); ft_thread_create (sched,controler,NULL,autom); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: >>>>>>>>>>> instant 1: >>>>>>>>>>> instant 2: >>>>>>>>>>> instant 3: suspend autom! >>>>>>>>>>> instant 4: >>>>>>>>>>> instant 5: >>>>>>>>>>> instant 6: >>>>>>>>>>> instant 7: >>>>>>>>>>> instant 8: >>>>>>>>>>> instant 9: >>>>>>>>>>> instant 10: >>>>>>>>>>> instant 11: >>>>>>>>>>> instant 12: >>>>>>>>>>> instant 13: >>>>>>>>>>> instant 14: >>>>>>>>>>> instant 15: >>>>>>>>>>> instant 16: >>>>>>>>>>> instant 17: >>>>>>>>>>> instant 18: resume autom! exit! end result */ ft_v1.0/tests/aut16.c0100644000374300000260000000561307477072670011756 0ustar fb#include "fthread.h" #include #include #include /* awaiting 2 events using two auxiliary automata */ ft_event_t e1,e2; /*************************************/ void awaiter_cleanup (void *args) { fprintf (stdout, "awaiter is killed! "); } DEFINE_AUTOMATON(awaiter) { void **args = ARGS; ft_event_t event = (ft_event_t) (args[0]); ft_event_t present = (ft_event_t) (args[1]); BEGIN_AUTOMATON STATE_AWAIT(0,event) { ft_thread_generate (present); GOTO(0); } END_AUTOMATON } DEFINE_AUTOMATON(both) { void **args = ARGS; ft_scheduler_t sched = (ft_scheduler_t)args[0]; ft_event_t event1 = (ft_event_t) args[1]; ft_event_t event2 = (ft_event_t) args[2]; BEGIN_AUTOMATON STATE(0) { void **v1 = malloc (2), **v2 = malloc (2); ft_event_t present = ft_event_create (sched); v1[0] = event1; v1[1] = present; ft_automaton_create (sched,awaiter,awaiter_cleanup,v1); v2[0] = event2; v2[1] = present; ft_automaton_create (sched,awaiter,awaiter_cleanup,v2); SET_LOCAL (present); } STATE_AWAIT(1,(ft_event_t)LOCAL) { fprintf (stdout, "event received! "); GOTO(1); } END_AUTOMATON } /*************************************/ void traceInstants (void *args) { int i = 0; for (i=0;i<20;i++) { fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i); ft_thread_cooperate (); } fprintf (stdout, "exit!\n"); exit (0); } void generator (void *args) { int i; for (i=0;i<3;i++) { ft_thread_cooperate_n (3); ft_thread_generate (e1); fprintf (stdout, "e1 generated! "); ft_thread_cooperate_n (1); ft_thread_generate (e2); fprintf (stdout, "e2 generated! "); } } int main(void) { void **v = malloc (3); ft_scheduler_t sched = ft_scheduler_create (); e1 = ft_event_create (sched); e2 = ft_event_create (sched); ft_thread_create (sched,traceInstants,NULL,NULL); ft_thread_create (sched,generator,NULL,NULL); v[0] = sched; v[1] = e1; v[2] = e2; ft_automaton_create (sched,both,NULL,v); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: >>>>>>>>>>> instant 1: >>>>>>>>>>> instant 2: >>>>>>>>>>> instant 3: e1 generated! event received! >>>>>>>>>>> instant 4: e2 generated! event received! >>>>>>>>>>> instant 5: >>>>>>>>>>> instant 6: >>>>>>>>>>> instant 7: e1 generated! event received! >>>>>>>>>>> instant 8: e2 generated! event received! >>>>>>>>>>> instant 9: >>>>>>>>>>> instant 10: >>>>>>>>>>> instant 11: e1 generated! event received! >>>>>>>>>>> instant 12: e2 generated! event received! >>>>>>>>>>> instant 13: >>>>>>>>>>> instant 14: >>>>>>>>>>> instant 15: >>>>>>>>>>> instant 16: >>>>>>>>>>> instant 17: >>>>>>>>>>> instant 18: >>>>>>>>>>> instant 19: exit! end result */ ft_v1.0/tests/aut17.c0100644000374300000260000000477307477072670011765 0ustar fb#include "fthread.h" #include #include #include /* two threads run in turn using an auxiliary automaton */ /*************************************/ DEFINE_AUTOMATON(switch_automaton) { void **args = ARGS; ft_event_t event = (ft_event_t) (args[0]); ft_thread_t thread1 = (ft_thread_t) (args[1]); ft_thread_t thread2 = (ft_thread_t) (args[2]); BEGIN_AUTOMATON STATE(0) { ft_scheduler_resume (thread1); } STATE_AWAIT (1,event) { ft_scheduler_suspend (thread1); ft_scheduler_resume (thread2); GOTO(2); } STATE_AWAIT (2,event) { ft_scheduler_suspend (thread2); ft_scheduler_resume (thread1); GOTO(1); } END_AUTOMATON } /*************************************/ void printer (void *args) { while (1) { fprintf (stdout, "%s",(char*)args); ft_thread_cooperate (); } } /*************************************/ void traceInstants (void *args) { int i = 0; for (i=0;i<20;i++) { fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i); ft_thread_cooperate (); } fprintf (stdout, "exit!\n"); exit (0); } void generator (void *args) { int i; for (i=0;i<10;i++) { ft_thread_cooperate_n (5); ft_thread_generate ((ft_event_t)args); fprintf (stdout, "event generated! "); } } int main(void) { ft_thread_t t1,t2; void **v = malloc (3); ft_scheduler_t sched = ft_scheduler_create (); ft_event_t event = ft_event_create (sched); ft_thread_create (sched,traceInstants,NULL,NULL); ft_thread_create (sched,generator,NULL,event); t1 = ft_thread_create (sched,printer,NULL,"1"); t2 = ft_thread_create (sched,printer,NULL,"2"); ft_scheduler_suspend (t1); ft_scheduler_suspend (t2); v[0] = event; v[1] = t1; v[2] = t2; ft_automaton_create (sched,switch_automaton,NULL,v); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: >>>>>>>>>>> instant 1: 1 >>>>>>>>>>> instant 2: 1 >>>>>>>>>>> instant 3: 1 >>>>>>>>>>> instant 4: 1 >>>>>>>>>>> instant 5: event generated! 1 >>>>>>>>>>> instant 6: 2 >>>>>>>>>>> instant 7: 2 >>>>>>>>>>> instant 8: 2 >>>>>>>>>>> instant 9: 2 >>>>>>>>>>> instant 10: event generated! 2 >>>>>>>>>>> instant 11: 1 >>>>>>>>>>> instant 12: 1 >>>>>>>>>>> instant 13: 1 >>>>>>>>>>> instant 14: 1 >>>>>>>>>>> instant 15: event generated! 1 >>>>>>>>>>> instant 16: 2 >>>>>>>>>>> instant 17: 2 >>>>>>>>>>> instant 18: 2 >>>>>>>>>>> instant 19: 2exit! end result */ ft_v1.0/tests/aut18.c0100644000374300000260000000247707477072670011765 0ustar fb#include "fthread.h" #include "stdio.h" /* SELECT */ ft_event_t a,b; DEFINE_AUTOMATON(awaiter) { ft_event_t events [2] = {a,b}; int result [2] = {0,0}; BEGIN_AUTOMATON STATE_SELECT(0,2,events,result) { fprintf (stdout, "result: [%d,%d] ",result[0],result[1]); GOTO_NEXT; } STATE(1) { fprintf (stdout, "exit!\n"); fflush (stdout); exit (0); } END_AUTOMATON } DEFINE_AUTOMATON(generator) { BEGIN_AUTOMATON STATE_STAY(0,5) { ft_thread_generate ((ft_event_t)ARGS); } END_AUTOMATON } /**************************************************/ void trace_instant (void *args) { int i = 1; while (1) { fprintf (stdout, "\ninstant %d: ",i); i++; ft_thread_cooperate (); } } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); a = ft_event_create (sched); b = ft_event_create (sched); ft_thread_create (sched,trace_instant,NULL,NULL); ft_automaton_create (sched,awaiter,NULL,NULL); ft_automaton_create (sched,generator,NULL,b); ft_automaton_create (sched,generator,NULL,a); ft_scheduler_start (sched); ft_exit (); return 0; } /* result instant 1: instant 2: instant 3: instant 4: instant 5: instant 6: result: [1,1] instant 7: exit! end result */ ft_v1.0/tests/aut19.c0100644000374300000260000000273507477072670011763 0ustar fb#include "fthread.h" #include "stdio.h" /* SELECT_N */ ft_event_t a,b; DEFINE_AUTOMATON(awaiter) { ft_event_t events [2] = {a,b}; int result [2] = {0,0}; BEGIN_AUTOMATON STATE_SELECT_N(0,2,events,result,5) { if (RETURN_CODE == ETIMEOUT) fprintf (stdout, "timeout! "); fprintf (stdout, "result: [%d,%d] ",result[0],result[1]); GOTO_NEXT; } STATE(1) { fprintf (stdout, "exit!\n"); fflush (stdout); exit (0); } END_AUTOMATON } DEFINE_AUTOMATON(generator) { BEGIN_AUTOMATON STATE_STAY(0,3) { fprintf (stdout,"generate! "); ft_thread_generate ((ft_event_t)ARGS); } END_AUTOMATON } /**************************************************/ void trace_instant (void *args) { int i = 1; for (i=0;;i++) { fprintf (stdout, "\ninstant %d: ",i); ft_thread_cooperate (); } fflush (stdout); exit(0); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); a = ft_event_create (sched); b = ft_event_create (sched); ft_thread_create (sched,trace_instant,NULL,NULL); ft_automaton_create (sched,awaiter,NULL,NULL); //ft_automaton_create (sched,generator,NULL,b); //ft_automaton_create (sched,generator,NULL,a); ft_scheduler_start (sched); ft_exit (); return 0; } /* result instant 0: instant 1: instant 2: instant 3: instant 4: instant 5: timeout! result: [0,0] instant 6: exit! end result */ ft_v1.0/tests/aut2.c0100644000374300000260000000222107477072670011661 0ustar fb#include "fthread.h" #include /* timeout with AWAIT_N */ ft_event_t event; DEFINE_AUTOMATON (autom) { BEGIN_AUTOMATON STATE_AWAIT_N(0,event,2) { if (RETURN_CODE == ETIMEOUT) fprintf (stdout, "timeout! "); IMMEDIATE (0); } END_AUTOMATON } /*********************************/ void traceInstants (void *args) { int i = 0; for (i=0;i<10;i++) { fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i); ft_thread_cooperate (); } fprintf (stdout, "exit!\n"); exit (0); } int main () { ft_scheduler_t sched = ft_scheduler_create (); event = ft_event_create (sched); ft_thread_create (sched,traceInstants,NULL,NULL); if (NULL == ft_automaton_create (sched,autom,NULL,NULL)) { fprintf (stdout, "cannot create automaton!!!\n"); } ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: >>>>>>>>>>> instant 1: >>>>>>>>>>> instant 2: timeout! >>>>>>>>>>> instant 3: >>>>>>>>>>> instant 4: timeout! >>>>>>>>>>> instant 5: >>>>>>>>>>> instant 6: timeout! >>>>>>>>>>> instant 7: >>>>>>>>>>> instant 8: timeout! >>>>>>>>>>> instant 9: exit! end result */ ft_v1.0/tests/aut3.c0100644000374300000260000000274107477072670011671 0ustar fb#include "fthread.h" #include ft_event_t event; DEFINE_AUTOMATON (autom) { BEGIN_AUTOMATON STATE_AWAIT_N(0,event,2) { if (RETURN_CODE == ETIMEOUT) fprintf (stdout, "timeout! "); else if (RETURN_CODE == OK) fprintf (stdout, "received! "); GOTO (0); } END_AUTOMATON } DEFINE_AUTOMATON (gen) { BEGIN_AUTOMATON STATE_STAY(0,2) { ft_thread_generate (event); fprintf (stdout, "generate! "); IMMEDIATE (0); } END_AUTOMATON } /*********************************/ void traceInstants (void *args) { int i = 0; for (i=0;i<10;i++) { fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i); ft_thread_cooperate (); } fprintf (stdout, "exit!\n"); exit (0); } int main () { ft_scheduler_t sched = ft_scheduler_create (); event = ft_event_create (sched); ft_thread_create (sched,traceInstants,NULL,NULL); if (NULL == ft_automaton_create (sched,autom,NULL,NULL)) { fprintf (stdout, "cannot create automaton!!!\n"); } ft_automaton_create (sched,gen,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: >>>>>>>>>>> instant 1: >>>>>>>>>>> instant 2: timeout! generate! >>>>>>>>>>> instant 3: >>>>>>>>>>> instant 4: generate! received! >>>>>>>>>>> instant 5: >>>>>>>>>>> instant 6: generate! received! >>>>>>>>>>> instant 7: >>>>>>>>>>> instant 8: generate! received! >>>>>>>>>>> instant 9: exit! end result */ ft_v1.0/tests/aut4.c0100644000374300000260000000455507477072670011677 0ustar fb#include "fthread.h" #include ft_event_t event; DEFINE_AUTOMATON (autom) { int c; BEGIN_AUTOMATON STATE_AWAIT (0,event) { fprintf (stdout, "received! "); } STATE_GET_VALUE(1,event,1,(void**)&c) { if (RETURN_CODE == ENEXT) fprintf (stdout, "no value #1 available! "); else if (RETURN_CODE == OK) fprintf (stdout, "get value #1 %d! ",c); GOTO (0); } END_AUTOMATON } void one_generation (ft_event_t event,ft_thread_t SELF) { ft_thread_generate_value (event,(void*)LOCAL); fprintf (stdout, "generate %d! ",(int)LOCAL); SET_LOCAL (LOCAL+1); } DEFINE_AUTOMATON (gen) { BEGIN_AUTOMATON STATE(0) { SET_LOCAL (45); } STATE_STAY (1,3) { one_generation (event,SELF); } STATE_STAY(2,3) { one_generation (event,SELF); one_generation (event,SELF); IMMEDIATE (1); } END_AUTOMATON } /*********************************/ void traceInstants (void *args) { int i = 0; for (i=0;i<20;i++) { fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i); ft_thread_cooperate (); } fprintf (stdout, "exit!\n"); exit (0); } int main () { ft_scheduler_t sched = ft_scheduler_create (); event = ft_event_create (sched); ft_thread_create (sched,traceInstants,NULL,NULL); if (NULL == ft_automaton_create (sched,autom,NULL,NULL)) { fprintf (stdout, "cannot create automaton!!!\n"); } ft_automaton_create (sched,gen,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: >>>>>>>>>>> instant 1: >>>>>>>>>>> instant 2: >>>>>>>>>>> instant 3: generate 45! received! >>>>>>>>>>> instant 4: no value #1 available! >>>>>>>>>>> instant 5: >>>>>>>>>>> instant 6: generate 46! generate 47! received! get value #1 47! >>>>>>>>>>> instant 7: >>>>>>>>>>> instant 8: >>>>>>>>>>> instant 9: generate 48! received! >>>>>>>>>>> instant 10: no value #1 available! >>>>>>>>>>> instant 11: >>>>>>>>>>> instant 12: generate 49! generate 50! received! get value #1 50! >>>>>>>>>>> instant 13: >>>>>>>>>>> instant 14: >>>>>>>>>>> instant 15: generate 51! received! >>>>>>>>>>> instant 16: no value #1 available! >>>>>>>>>>> instant 17: >>>>>>>>>>> instant 18: generate 52! generate 53! received! get value #1 53! >>>>>>>>>>> instant 19: exit! end result */ ft_v1.0/tests/aut5.c0100644000374300000260000000457107477072670011676 0ustar fb#include "fthread.h" #include DEFINE_AUTOMATON (autom) { ft_event_t event = (ft_event_t)ARGS; int c; BEGIN_AUTOMATON STATE_AWAIT (0,event) { fprintf (stdout, "received! "); } STATE_GET_VALUE (1,event,1,(void**)&c) { if (RETURN_CODE == ENEXT) fprintf (stdout, "no value #1 available! "); else if (RETURN_CODE == OK) fprintf (stdout, "get value #1 %d! ",c); GOTO (0); } END_AUTOMATON } void one_generation (ft_event_t event,ft_thread_t SELF) { ft_thread_generate_value (event,(void*)LOCAL); fprintf (stdout, "generate %d! ",(int)LOCAL); SET_LOCAL (LOCAL+1); } DEFINE_AUTOMATON (gen) { ft_event_t event = (ft_event_t)ARGS; BEGIN_AUTOMATON STATE(0) { SET_LOCAL (45); } STATE_STAY(1,3) { one_generation (event,SELF); } STATE_STAY(2,3) { one_generation (event,SELF); one_generation (event,SELF); IMMEDIATE (1); } END_AUTOMATON } /*********************************/ void traceInstants (void *args) { int i = 0; for (i=0;i<20;i++) { fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i); ft_thread_cooperate (); } fprintf (stdout, "exit!\n"); exit (0); } int main () { ft_scheduler_t sched = ft_scheduler_create (); ft_event_t event = ft_event_create (sched); ft_thread_create (sched,traceInstants,NULL,NULL); ft_automaton_create (sched,autom,NULL,event); ft_automaton_create (sched,gen,NULL,event); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: >>>>>>>>>>> instant 1: >>>>>>>>>>> instant 2: >>>>>>>>>>> instant 3: generate 45! received! >>>>>>>>>>> instant 4: no value #1 available! >>>>>>>>>>> instant 5: >>>>>>>>>>> instant 6: generate 46! generate 47! received! get value #1 47! >>>>>>>>>>> instant 7: >>>>>>>>>>> instant 8: >>>>>>>>>>> instant 9: generate 48! received! >>>>>>>>>>> instant 10: no value #1 available! >>>>>>>>>>> instant 11: >>>>>>>>>>> instant 12: generate 49! generate 50! received! get value #1 50! >>>>>>>>>>> instant 13: >>>>>>>>>>> instant 14: >>>>>>>>>>> instant 15: generate 51! received! >>>>>>>>>>> instant 16: no value #1 available! >>>>>>>>>>> instant 17: >>>>>>>>>>> instant 18: generate 52! generate 53! received! get value #1 53! >>>>>>>>>>> instant 19: exit! end result */ ft_v1.0/tests/aut6.c0100644000374300000260000002652407477072670011701 0ustar fb#include "fthread.h" #include ft_event_t event; DEFINE_AUTOMATON (autom) { BEGIN_AUTOMATON STATE_AWAIT (0,event) { fprintf (stdout, "*"); GOTO(0); } END_AUTOMATON } /*********************************/ void traceInstants (void *args) { int i = 0; while (1) { fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i++); ft_thread_cooperate (); } } void generator (void *args) { int i; for (i=0;i<2;i++) { ft_thread_cooperate_n (10); fprintf (stdout, "event generated! "); ft_thread_generate (event); } ft_thread_cooperate (); fprintf (stdout, "exit\n"); exit (0); } int main () { int i; ft_scheduler_t sched = ft_scheduler_create (); ft_thread_create (sched,traceInstants,NULL,NULL); for (i=0;i<5000;i++) ft_automaton_create (sched,autom,NULL,NULL); ft_thread_create (sched,generator,NULL,NULL); event = ft_event_create (sched); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: >>>>>>>>>>> instant 1: >>>>>>>>>>> instant 2: >>>>>>>>>>> instant 3: >>>>>>>>>>> instant 4: >>>>>>>>>>> instant 5: >>>>>>>>>>> instant 6: >>>>>>>>>>> instant 7: >>>>>>>>>>> instant 8: >>>>>>>>>>> instant 9: >>>>>>>>>>> instant 10: event generated! ******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** >>>>>>>>>>> instant 11: >>>>>>>>>>> instant 12: >>>>>>>>>>> instant 13: >>>>>>>>>>> instant 14: >>>>>>>>>>> instant 15: >>>>>>>>>>> instant 16: >>>>>>>>>>> instant 17: >>>>>>>>>>> instant 18: >>>>>>>>>>> instant 19: >>>>>>>>>>> instant 20: event generated! ******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** >>>>>>>>>>> instant 21: exit end result */ ft_v1.0/tests/aut7.c0100644000374300000260000000304507477072670011673 0ustar fb#include "fthread.h" #include #include /*************************************/ ft_event_t e1, e2; /*************************************/ DEFINE_AUTOMATON(behav1) { BEGIN_AUTOMATON STATE(0) fprintf (stdout,"broadcast e1\n"); ft_thread_generate (e1); STATE(1) fprintf (stdout,"wait e2\n"); STATE_AWAIT(2,e2) fprintf (stdout,"receive e2\n"); STATE(3) fprintf (stdout,"end of behav1\n"); END_AUTOMATON } DEFINE_AUTOMATON(behav2) { BEGIN_AUTOMATON STATE(0) fprintf (stdout,"wait e1\n"); STATE_AWAIT(1,e1) fprintf (stdout,"receive e1\n"); STATE(2) ft_thread_generate (e2); fprintf (stdout,"broadcast e2\n"); STATE(3) fprintf (stdout,"end of behav2\n"); END_AUTOMATON } /*************************************/ void traceInstants (void *args) { int i = 0; for (i=0;i<3;i++) { //fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i); ft_thread_cooperate (); } fprintf (stdout, "exit!\n"); exit (0); } int main(void) { ft_scheduler_t sched = ft_scheduler_create (); e1 = ft_event_create (sched); e2 = ft_event_create (sched); ft_thread_create (sched,traceInstants,NULL,NULL); ft_automaton_create (sched,behav1,NULL,NULL); ft_automaton_create (sched,behav2,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result broadcast e1 wait e2 wait e1 receive e1 broadcast e2 end of behav2 receive e2 end of behav1 exit! end result */ ft_v1.0/tests/aut8.c0100644000374300000260000000303207477072670011670 0ustar fb#include "fthread.h" #include #include /* automata can be joined, just as standard threads */ /*************************************/ ft_event_t e1, e2; ft_thread_t a1,a2; /*************************************/ DEFINE_AUTOMATON(behav1) { BEGIN_AUTOMATON STATE(0) fprintf (stdout,"broadcast e1\n"); ft_thread_generate (e1); STATE(1) fprintf (stdout,"wait e2\n"); STATE_AWAIT(2,e2) fprintf (stdout,"receive e2\n"); STATE(3) fprintf (stdout,"end of behav1\n"); END_AUTOMATON } DEFINE_AUTOMATON(behav2) { BEGIN_AUTOMATON STATE(0) fprintf (stdout,"wait e1\n"); STATE_AWAIT(1,e1) fprintf (stdout,"receive e1\n"); STATE(2) ft_thread_generate (e2); fprintf (stdout,"broadcast e2\n"); STATE(3) fprintf (stdout,"end of behav2\n"); END_AUTOMATON } /*************************************/ void waiter (void *args) { ft_thread_join (a1); ft_thread_join (a2); fprintf (stdout, "exit!\n"); exit (0); } int main(void) { ft_scheduler_t sched = ft_scheduler_create (); e1 = ft_event_create (sched); e2 = ft_event_create (sched); ft_thread_create (sched,waiter,NULL,NULL); a1 = ft_automaton_create (sched,behav1,NULL,NULL); a2 = ft_automaton_create (sched,behav2,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result broadcast e1 wait e2 wait e1 receive e1 broadcast e2 end of behav2 receive e2 end of behav1 exit! end result */ ft_v1.0/tests/aut9.c0100644000374300000260000000311107477072670011667 0ustar fb#include "fthread.h" #include #include /* automata can be suspended and resumed, just as standard threads */ /*************************************/ ft_thread_t a; /*************************************/ DEFINE_AUTOMATON(behav1) { BEGIN_AUTOMATON STATE(0) fprintf (stdout,"* "); GOTO(0); END_AUTOMATON } /*************************************/ void traceInstants (void *args) { int i = 0; for (i=0;i<20;i++) { fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i); ft_thread_cooperate (); } fprintf (stdout, "exit!\n"); exit (0); } void waiter (void *args) { while (1) { ft_thread_cooperate_n (3); ft_scheduler_suspend (a); ft_thread_cooperate_n (3); ft_scheduler_resume (a); } } int main(void) { ft_scheduler_t sched = ft_scheduler_create (); ft_thread_create (sched,traceInstants,NULL,NULL); ft_thread_create (sched,waiter,NULL,NULL); a = ft_automaton_create (sched,behav1,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: * >>>>>>>>>>> instant 1: * >>>>>>>>>>> instant 2: * >>>>>>>>>>> instant 3: * >>>>>>>>>>> instant 4: >>>>>>>>>>> instant 5: >>>>>>>>>>> instant 6: >>>>>>>>>>> instant 7: * >>>>>>>>>>> instant 8: * >>>>>>>>>>> instant 9: * >>>>>>>>>>> instant 10: >>>>>>>>>>> instant 11: >>>>>>>>>>> instant 12: >>>>>>>>>>> instant 13: * >>>>>>>>>>> instant 14: * >>>>>>>>>>> instant 15: * >>>>>>>>>>> instant 16: >>>>>>>>>>> instant 17: >>>>>>>>>>> instant 18: >>>>>>>>>>> instant 19: * exit! end result */ ft_v1.0/tests/aux/0040755000374300000260000000000007477072670011445 5ustar fbft_v1.0/tests/aux/testOne0100745000374300000260000000056507477072670013016 0ustar fbINCL_DIR=../include LIB_DIR=../lib LIBS="-lfthread -lpthread" #LIBS="-lposix4 -lfthread -lpthread" ############################################################### echo "test of $1"; rm -f aux/EXPECTED aux/RESULT gcc -Wall -O3 -D_REENTRANT -I $INCL_DIR -L $LIB_DIR $1.c $LIBS a.out > aux/RESULT aux/extractresult.sh $1.c > aux/EXPECTED diff -w aux/EXPECTED aux/RESULT ft_v1.0/tests/aux/RESULT0100644000374300000260000000043707477072670012407 0ustar fb>>>>>>>>>>> instant 0 *>>>>>>>>>>> instant 1 *>>>>>>>>>>> instant 2 *>>>>>>>>>>> instant 3 *>>>>>>>>>>> instant 4 *>>>>>>>>>>> instant 5 *>>>>>>>>>>> instant 6 *>>>>>>>>>>> instant 7 *>>>>>>>>>>> instant 8 *>>>>>>>>>>> instant 9 *>>>>>>>>>>> instant 10 *stop >>>>>>>>>>> instant 11 exit ft_v1.0/tests/aux/EXPECTED0100644000374300000260000000043707477072670012572 0ustar fb>>>>>>>>>>> instant 0 *>>>>>>>>>>> instant 1 *>>>>>>>>>>> instant 2 *>>>>>>>>>>> instant 3 *>>>>>>>>>>> instant 4 *>>>>>>>>>>> instant 5 *>>>>>>>>>>> instant 6 *>>>>>>>>>>> instant 7 *>>>>>>>>>>> instant 8 *>>>>>>>>>>> instant 9 *>>>>>>>>>>> instant 10 *stop >>>>>>>>>>> instant 11 exit ft_v1.0/tests/aux/testAll0100755000374300000260000000007507477072670013002 0ustar fbfor prog in *.c do aux/testOne `basename $prog .c` done ft_v1.0/tests/aux/extractresult.perl0100755000374300000260000000016407477072670015243 0ustar fb#!/usr/bin/perl while (<>) { if (m!/\* result! .. m!/end result \*/!) { print unless m!result!; } } ft_v1.0/tests/aux/extractresult.sh0100755000374300000260000000016707477072670014716 0ustar fb#!/bin/sh cat $1 | awk 'BEGIN { aff=0 } /end result \*/ { aff=0 } { if(aff==1) { print $0 }} /\/\* result/ { aff=1 }'ft_v1.0/tests/creation1.c0100644000374300000260000000212507477072670012676 0ustar fb#include "fthread.h" #include /* use of ft_pthread to detach created threads. 5000 threads are created, one after the other. Without calling detach, it would not be possible to create as many threads. */ ft_thread_t th; ft_scheduler_t sched; void func (void *args) { int i = (int)args; if (i%100 == 0) { fprintf (stdout, "%d ",i); fflush (stdout); } } void creator (void *args) { int i; for (i=0;i<5000;i++) { th = ft_thread_create (sched,func,NULL,(void*)i); pthread_detach (ft_pthread (th)); ft_thread_cooperate_n (100); ft_thread_join (th); } fprintf (stdout, "\nexit\n"); exit (0); } int main () { sched = ft_scheduler_create (); ft_scheduler_start (sched); ft_thread_create (sched,creator,NULL,NULL); ft_exit (); return 0; } /* result 0 100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400 1500 1600 1700 1800 1900 2000 2100 2200 2300 2400 2500 2600 2700 2800 2900 3000 3100 3200 3300 3400 3500 3600 3700 3800 3900 4000 4100 4200 4300 4400 4500 4600 4700 4800 4900 exit end result */ ft_v1.0/tests/double-sched.c0100644000374300000260000000277607477072670013363 0ustar fb#include "fthread.h" #include ft_scheduler_t slow,fast; ft_event_t sync_slow,sync_fast; ft_thread_t slow_th,fast_th; /**********************************/ void behav (int n,void* args){ ft_event_t evt = (ft_event_t)args; while(1){ ft_thread_await(evt); fprintf (stderr,"%d",n); ft_thread_cooperate (); } } void behav0 (void* args){ behav (0,args); } void behav1 (void* args){ behav (1,args); } /**********************************/ void fast_pilot (void *args) { while (1) { ft_thread_generate (sync_fast); ft_thread_cooperate_n (10); } } void slow_pilot (void *args) { while (1) { ft_thread_generate (sync_slow); ft_thread_cooperate_n (100); } } void counter (void *args) { int i; for (i=0;i<10000;i++) { ft_thread_cooperate (); } fprintf (stdout,"the output is not deterministic\n"); fprintf (stderr,"\n"); exit (0); } /**********************************/ int main (void) { slow = ft_scheduler_create (); fast = ft_scheduler_create (); sync_fast = ft_event_create (fast); sync_slow = ft_event_create (slow); fast_th = ft_thread_create (fast,fast_pilot,NULL,NULL); slow_th = ft_thread_create (slow,slow_pilot,NULL,NULL); ft_thread_create (slow,behav1,NULL,sync_slow); ft_thread_create (fast,behav0,NULL,sync_fast); ft_thread_create (slow,counter,NULL,NULL); ft_scheduler_start (fast); ft_scheduler_start (slow); ft_exit(); return 0; } /* result the output is not deterministic end result */ ft_v1.0/tests/error0.c0100644000374300000260000000055507477072670012227 0ustar fb#include "fthread.h" #include "stdio.h" /* cooperate not executed in a thread */ int main (void) { ft_scheduler_t sched = ft_scheduler_create (); ft_scheduler_start (sched); if (OK != ft_thread_cooperate ()) { fprintf (stdout,"cooperate not possible\n"); exit (0); } ft_exit (); return 0; } /* result cooperate not possible end result */ ft_v1.0/tests/error1.c0100644000374300000260000000167707477072670012236 0ustar fb#include "fthread.h" #include #include /* stop an unlinked thread */ void cleanup (void *args) { fprintf (stdout,"cleanup!!!!\n"); exit (0); } void f (void *args) { ft_thread_unlink(); fprintf (stdout,"start sleeping\n"); sleep (1); fprintf (stdout,"end of sleep\n"); exit (0); } void stopThread (void *args) { ft_thread_cooperate_n (1000); fprintf (stdout,"stop thread\n"); if (OK != ft_scheduler_stop ((ft_thread_t)args)){ fprintf (stdout,"cannot stop an unlinked thread\n"); }else fprintf (stdout,"stop succeeded\n"); exit (0); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); ft_thread_t th1 = ft_thread_create (sched,f,cleanup,NULL); ft_thread_create (sched,stopThread,NULL,th1); ft_scheduler_start (sched); sleep(10); fprintf (stdout,"exit\n"); ft_exit(); return 0; } /* result start sleeping stop thread cannot stop an unlinked thread end result */ ft_v1.0/tests/error10.c0100644000374300000260000000064307477072670012306 0ustar fb#include "fthread.h" #include "stdio.h" /* cannot create an event before its scheduler */ int main(void) { ft_scheduler_t sched = NULL; if (NULL == ft_event_create (sched)){ fprintf (stdout,"cannot create an event before its scheduler\n"); } sched = ft_scheduler_create (); ft_scheduler_start (sched); exit (0); return 0; } /* result cannot create an event before its scheduler end result */ ft_v1.0/tests/error11.c0100644000374300000260000000056407477072670012311 0ustar fb#include "fthread.h" #include "stdio.h" /* scheduler must be created before being started */ int main(void) { ft_scheduler_t sched = NULL; if (EBADCREATE == ft_scheduler_start (sched)){ fprintf (stdout,"scheduler must be created before being started\n"); } exit (0); return 0; } /* result scheduler must be created before being started end result */ ft_v1.0/tests/error12.c0100644000374300000260000000170207477072670012305 0ustar fb#include "fthread.h" #include "stdio.h" /* bad uses of ft_thread_self */ void behav (void *args) { ft_thread_t self; fprintf (stdout, "running\n"); self = ft_thread_self (); if (self == NULL) fprintf (stdout, "bad self 4\n"); ft_thread_unlink (); self = ft_thread_self (); if (self == NULL) fprintf (stdout, "bad self 5\n"); fprintf (stdout, "ending\n"); exit (0); } int main (void) { ft_thread_t self; ft_scheduler_t sched; ft_thread_t th; self = ft_thread_self (); if (self == NULL) fprintf (stdout, "bad self 1\n"); sched = ft_scheduler_create(); th = ft_thread_create(sched,behav,NULL,NULL); self = ft_thread_self (); if (self == NULL) fprintf (stdout, "bad self 2\n"); ft_scheduler_start (sched); self = ft_thread_self (); if (self == NULL) fprintf (stdout, "bad self 3\n"); ft_exit (); return 0; } /* result bad self 1 bad self 2 bad self 3 running ending end result */ ft_v1.0/tests/error13.c0100644000374300000260000000213007477072670012302 0ustar fb#include "fthread.h" #include "stdio.h" /* bad uses of ft_thread_scheduler */ void behav (void *args) { ft_scheduler_t scheduler; fprintf (stdout, "running\n"); scheduler = ft_thread_scheduler (); if (scheduler == NULL) fprintf (stdout, "bad scheduler 4\n"); ft_thread_unlink (); scheduler = ft_thread_scheduler (); if (scheduler == NULL) fprintf (stdout, "bad scheduler 5 (unlinked)\n"); fprintf (stdout, "ending\n"); exit (0); } int main (void) { ft_scheduler_t scheduler; ft_scheduler_t sched; scheduler = ft_thread_scheduler (); if (scheduler == NULL) fprintf (stdout, "bad scheduler 1\n"); sched = ft_scheduler_create(); scheduler = ft_thread_scheduler (); if (scheduler == NULL) fprintf (stdout, "bad scheduler 2\n"); ft_thread_create(sched,behav,NULL,NULL); ft_scheduler_start(sched); scheduler = ft_thread_scheduler (); if (scheduler == NULL) fprintf (stdout, "bad scheduler 3\n"); ft_exit (); return 0; } /* result bad scheduler 1 bad scheduler 2 bad scheduler 3 running bad scheduler 5 (unlinked) ending end result */ ft_v1.0/tests/error14.c0100644000374300000260000000067207477072670012314 0ustar fb#include "fthread.h" #include "stdio.h" /* event must be created before broadcast */ int main (void) { ft_scheduler_t sched = NULL; ft_event_t event = NULL; sched = ft_scheduler_create (); ft_scheduler_start (sched); //ft_event_create (&event,sched); if (EBADCREATE == ft_scheduler_broadcast (event)){ fprintf (stdout,"bad event broadcast\n"); } exit (0); return 0; } /* result bad event broadcast end result */ ft_v1.0/tests/error15.c0100644000374300000260000000146507477072670012316 0ustar fb#include "fthread.h" #include /* bad event creation */ void f (void *args) { int v, *cell = &v; if (EBADCREATE == ft_thread_generate ((ft_event_t)args)) { fprintf (stdout,"bad event creation\n"); } if (EBADCREATE == ft_thread_await ((ft_event_t)args)) { fprintf (stdout,"bad event creation\n"); } if (EBADCREATE == ft_thread_get_value ((ft_event_t)args,0,(void**)&cell)) { fprintf (stdout,"bad event creation\n"); } exit (0); } int main (void) { ft_scheduler_t sched1 = NULL; ft_event_t evt = NULL; sched1 = ft_scheduler_create (); //evt = ft_event_create (sched1); ft_thread_create (sched1,f,NULL,evt); ft_scheduler_start (sched1); ft_exit (); return 0; } /* result bad event creation bad event creation bad event creation end result */ ft_v1.0/tests/error16.c0100644000374300000260000000054407477072670012314 0ustar fb#include "fthread.h" #include "stdio.h" /* a thread can be created before the scheduler */ int main (void) { ft_scheduler_t sched = NULL; if (EBADCREATE == ft_scheduler_start (sched)){ fprintf (stdout,"scheduler bad creation\n"); } fprintf (stdout,"exit\n"); exit (0); return 0; } /* result scheduler bad creation exit end result */ ft_v1.0/tests/error2.c0100644000374300000260000000401607477072670012225 0ustar fb#include "fthread.h" #include #include /* actions in an unlinked thread */ void f (void *args) { int v, *cell = &v; ft_thread_unlink (); if (OK != ft_thread_cooperate ()){ fprintf (stdout,"cannot cooperate in an unlinked thread\n"); } if (OK != ft_thread_cooperate_n (10)){ fprintf (stdout,"cannot cooperate_n in an unlinked thread\n"); } if (OK != ft_thread_unlink ()){ fprintf (stdout,"cannot unlink an unlinked thread\n"); } if (OK != ft_thread_generate ((ft_event_t)args)){ fprintf (stdout,"cannot generate event in an unlinked thread\n"); } if (OK != ft_scheduler_broadcast ((ft_event_t)args)){ fprintf (stdout,"cannot broadcast event in an unlinked thread\n"); }else fprintf (stdout,"CAN broadcast event in an unlinked thread\n"); if (OK != ft_thread_await ((ft_event_t)args)){ fprintf (stdout,"cannot await event in an unlinked thread\n"); } if (OK != ft_thread_await_n ((ft_event_t)args,10)){ fprintf (stdout,"cannot await_n event in an unlinked thread\n"); } if (OK != ft_thread_generate_value ((ft_event_t)args,(void*)3)){ fprintf (stdout,"cannot generate valued event in an unlinked thread\n"); } if (OK != ft_thread_get_value ((ft_event_t)args,0,(void**)&cell)){ fprintf (stdout,"cannot get valued of an event in an unlinked thread\n"); } exit(0); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); ft_event_t evt = ft_event_create (sched); ft_thread_create (sched,f,NULL,evt); sleep(1); ft_scheduler_start (sched); ft_exit (); return 0; } /* result cannot cooperate in an unlinked thread cannot cooperate_n in an unlinked thread cannot unlink an unlinked thread cannot generate event in an unlinked thread CAN broadcast event in an unlinked thread cannot await event in an unlinked thread cannot await_n event in an unlinked thread cannot generate valued event in an unlinked thread cannot get valued of an event in an unlinked thread end result */ ft_v1.0/tests/error3.c0100644000374300000260000000115507477072670012227 0ustar fb#include "fthread.h" #include #include /* join in an unlinked thread */ void j (void *args) { ft_thread_unlink (); if (OK != ft_thread_join ((ft_thread_t)args)){ fprintf (stdout,"cannot join in an unlinked thread\n"); } exit (0); } void n (void *args) { while (1) ft_thread_cooperate (); } int main(void) { ft_scheduler_t sched = ft_scheduler_create (); ft_thread_t th2 = ft_thread_create (sched,n,NULL,NULL); ft_thread_create (sched,j,NULL,th2); ft_scheduler_start (sched); ft_exit (); return 0; } /* result cannot join in an unlinked thread end result */ ft_v1.0/tests/error4.c0100644000374300000260000000104307477072670012224 0ustar fb#include "fthread.h" #include /* link in an already linked thread */ void f (void *args) { if (OK != ft_thread_link ((ft_scheduler_t)args)) { fprintf (stdout,"cannot link an already linked thread\n"); } exit(0); } int main(void) { ft_scheduler_t sched1 = ft_scheduler_create (), sched2 = ft_scheduler_create (); ft_thread_create (sched1,f,NULL,sched2); ft_scheduler_start (sched1); ft_scheduler_start (sched2); ft_exit (); return 0; } /* result cannot link an already linked thread end result */ ft_v1.0/tests/error5.c0100644000374300000260000000151707477072670012233 0ustar fb#include "fthread.h" #include /* get value of an event which is in a different scheduler */ void f (void *args) { int v, *cell = &v; if (EBADLINK == ft_thread_generate ((ft_event_t)args)) { fprintf (stdout,"cannot generate event in another scheduler\n"); } if (EBADLINK == ft_thread_get_value ((ft_event_t)args,0,(void**)&cell)) { fprintf (stdout,"cannot get value from another scheduler\n"); } exit (0); } int main (void) { ft_scheduler_t sched1 = ft_scheduler_create (), sched2 = ft_scheduler_create (); ft_event_t evt = ft_event_create (sched2); ft_thread_create (sched1,f,NULL,evt); ft_scheduler_start (sched1); ft_scheduler_start (sched2); ft_exit (); return 0; } /* result cannot generate event in another scheduler cannot get value from another scheduler end result */ ft_v1.0/tests/error6.c0100644000374300000260000000153607477072670012235 0ustar fb#include "fthread.h" #include #include "stdio.h" /* timeout */ void f (void *args) { int res; if (ETIMEOUT == (res = ft_thread_await_n ((ft_event_t)args,10))){ fprintf (stdout,"await_n reaches timeout\n"); } while (1) ft_thread_cooperate (); } void g (void *args) { int res; ft_thread_cooperate (); if (ETIMEOUT == (res = ft_thread_join_n ((ft_thread_t)args,20))){ fprintf (stdout,"join_n reaches timeout\n"); }else fprintf (stdout,"join_n %d\n",res); exit (0); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); ft_event_t evt = ft_event_create (sched); ft_thread_t th1 = ft_thread_create (sched,f,NULL,evt); ft_thread_create (sched,g,NULL,th1); ft_scheduler_start (sched); ft_exit (); return 0; } /* result await_n reaches timeout join_n reaches timeout end result */ ft_v1.0/tests/error7.c0100644000374300000260000000141707477072670012234 0ustar fb#include "fthread.h" #include #include /* join with different schedulers */ void f (void *args) { ft_thread_cooperate_n (100); } void g (void *args) { if (OK != ft_thread_join ((ft_thread_t)args)) { fprintf (stdout,"cannot join a thread run by a distinct scheduler\n"); }else fprintf (stdout,"CAN join a thread run by a distinct scheduler\n"); exit (0); } int main (void) { ft_scheduler_t sched1 = ft_scheduler_create (), sched2 = ft_scheduler_create (); ft_thread_t th1 = ft_thread_create(sched1,f,NULL,sched2); ft_thread_create(sched2,g,NULL,th1); sleep(1); ft_scheduler_start(sched1); ft_scheduler_start(sched2); ft_exit (); return 0; } /* result CAN join a thread run by a distinct scheduler end result */ ft_v1.0/tests/error8.c0100644000374300000260000000170207477072670012232 0ustar fb#include "fthread.h" #include /* NEXT produced at next instant when no value is available */ void f (void *args) { int i,res; int v, *cell = &v; for (i=0;;i++) { if (ENEXT == (res = ft_thread_get_value((ft_event_t)args,i,(void**)&cell))) { fprintf (stdout,"next instant "); break; }else fprintf (stdout,"get: %d\n",res); } fprintf (stdout,"exit\n"); exit (0); } void traceInstants (void *args) { int i = 0; while (1) { fprintf (stdout,"\n>>>>>>>>>>> instant %d: ",i++); ft_thread_cooperate (); } } int main (void) { ft_scheduler_t sched1 = ft_scheduler_create (); ft_thread_t th1; ft_event_t evt = ft_event_create (sched1); ft_thread_create (sched1,traceInstants,NULL,NULL); th1 = ft_thread_create(sched1,f,NULL,evt); ft_scheduler_start (sched1); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: >>>>>>>>>>> instant 1: next instant exit end result */ ft_v1.0/tests/error9.c0100644000374300000260000000113607477072670012234 0ustar fb#include "fthread.h" #include "stdio.h" /* a thread can be created before the scheduler */ void pr (void *text) { int i; for (i=0;i<10;i++) { fprintf (stdout,"%s",(char*)text); ft_thread_cooperate (); } } int main(void) { ft_scheduler_t sched = NULL; if (NULL == ft_thread_create (sched,pr,NULL,"Hello ")){ fprintf (stdout,"cannot create a thread before its scheduler\n"); } sched = ft_scheduler_create(); ft_scheduler_start (sched); fprintf (stdout,"exit\n"); exit (0); return 0; } /* result cannot create a thread before its scheduler exit end result */ ft_v1.0/tests/makefile0100644000374300000260000000073707477072670012354 0ustar fb#################################################### CC = gcc -Wall -O3 -D_REENTRANT -I../include -L../lib LIBS = -lfthread -lpthread #LIBS = -posix4 -lfthread -lpthread # for solaris ############ C code to executable code ##################### .c : $(CC) $< $(LIBS) a.out #################################################### all: aux/testAll #################################################### clean: rm -f *~ a.out ####################################################ft_v1.0/tests/prodcons.h0100644000374300000260000000036007477072670012644 0ustar fb#define PRODUCED 5000 // number of produced values #define FILE_SIZE 20 // size of files #define MAX_THREADS 5 // number of threads #define PROCESSING 1000000 // processing delay #define PRINT(s,v) fprintf (stderr,s,v) ft_v1.0/tests/select1.c0100644000374300000260000000275007477072670012355 0ustar fb#include "fthread.h" #include "stdio.h" /* use of select to await 2 events */ ft_event_t a,b; void awaiter (void *args) { ft_event_t events [2] = {a,b}; int result [2] = {0,0}; ft_thread_select (2,events,result); fprintf (stdout, "result: [%d,%d] ",result[0],result[1]); if (result[0] == 0 || result[1] == 0) { ft_thread_await (result[0]==0 ? events[0] : events[1]); } fprintf (stdout, "both received! "); ft_thread_cooperate (); fprintf (stdout, "exit!\n"); exit (0); } void trace_instant (void *args) { int i = 1; while (1) { fprintf (stdout, "\ninstant %d: ",i); i++; ft_thread_cooperate (); } } void agenerator (void *args) { ft_thread_cooperate_n (3); fprintf (stdout, "event a generated! "); ft_thread_generate (a); } void bgenerator (void *args) { ft_thread_cooperate_n (3); fprintf (stdout, "event b generated! "); ft_thread_generate (b); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); a = ft_event_create (sched); b = ft_event_create (sched); ft_thread_create (sched,trace_instant,NULL,NULL); ft_thread_create (sched,agenerator,NULL,NULL); ft_thread_create (sched,awaiter,NULL,NULL); ft_thread_create (sched,bgenerator,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result instant 1: instant 2: instant 3: instant 4: event a generated! result: [1,0] event b generated! both received! instant 5: exit! end result */ ft_v1.0/tests/select2.c0100644000374300000260000000177207477072670012361 0ustar fb#include "fthread.h" #include "stdio.h" /* use of select_n to limit the waiting */ ft_event_t a,b; void awaiter (void *args) { ft_event_t events [2] = {a,b}; int result [2] = {0,0}; ft_thread_select_n (2,events,result,10); fprintf (stdout, "result: [%d,%d] ",result[0],result[1]); ft_thread_cooperate (); fprintf (stdout, "exit!\n"); exit (0); } void trace_instant (void *args) { int i = 1; while (1) { fprintf (stdout, "\ninstant %d: ",i); i++; ft_thread_cooperate (); } } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); a = ft_event_create (sched); b = ft_event_create (sched); ft_thread_create (sched,trace_instant,NULL,NULL); ft_thread_create (sched,awaiter,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result instant 1: instant 2: instant 3: instant 4: instant 5: instant 6: instant 7: instant 8: instant 9: instant 10: instant 11: result: [0,0] instant 12: exit! end result */ ft_v1.0/tests/select3.c0100644000374300000260000000263007477072670012354 0ustar fb#include "fthread.h" #include "stdio.h" /* use of select_n to react to the absence of an event */ ft_event_t a; void awaiter (void *args) { ft_event_t events [1] = {a}; int result [1] = {0}; ft_thread_select_n (1,events,result,1); fprintf (stdout, "result: [%d] ",result[0]); if (result[0] == 1) fprintf (stdout, "a is present! "); else fprintf (stdout, "a was absent! "); ft_thread_cooperate (); ft_thread_select_n (1,events,result,1); fprintf (stdout, "result: [%d] ",result[0]); if (result[0] == 1) fprintf (stdout, "a is present! "); else fprintf (stdout, "a was absent! "); ft_thread_cooperate (); fprintf (stdout, "exit!\n"); exit (0); } void trace_instant (void *args) { int i = 1; while (1) { fprintf (stdout, "\ninstant %d: ",i); i++; ft_thread_cooperate (); } } void agenerator (void *args) { fprintf (stdout, "event a generated! "); ft_thread_generate (a); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); a = ft_event_create (sched); ft_thread_create (sched,trace_instant,NULL,NULL); ft_thread_create (sched,agenerator,NULL,NULL); ft_thread_create (sched,awaiter,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result instant 1: event a generated! result: [1] a is present! instant 2: instant 3: result: [0] a was absent! instant 4: exit! end result */ ft_v1.0/tests/select4.c0100644000374300000260000000262607477072670012362 0ustar fb#include "fthread.h" #include "stdio.h" /* use of select to await 1 event amongst 2 */ ft_event_t a,b; void awaiter (void *args) { ft_event_t events [2] = {a,b}; int result [2] = {0,0}; ft_thread_select (2,events,result); fprintf (stdout, "result: [%d,%d] ",result[0],result[1]); if (result[0]) fprintf (stdout, "a received! "); else fprintf (stdout, "b received! "); ft_thread_cooperate (); fprintf (stdout, "exit!\n"); exit (0); } void trace_instant (void *args) { int i = 1; while (1) { fprintf (stdout, "\ninstant %d: ",i); i++; ft_thread_cooperate (); } } void agenerator (void *args) { ft_thread_cooperate_n (2); fprintf (stdout, "event a generated! "); ft_thread_generate (a); } void bgenerator (void *args) { ft_thread_cooperate_n (4); fprintf (stdout, "event b generated! "); ft_thread_generate (b); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); a = ft_event_create (sched); b = ft_event_create (sched); ft_thread_create (sched,trace_instant,NULL,NULL); ft_thread_create (sched,agenerator,NULL,NULL); ft_thread_create (sched,awaiter,NULL,NULL); ft_thread_create (sched,bgenerator,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result instant 1: instant 2: instant 3: event a generated! result: [1,0] a received! instant 4: exit! end result */ ft_v1.0/tests/test0.c0100644000374300000260000000126007477072670012047 0ustar fb#include "fthread.h" #include "stdio.h" void h(void *id) { int i; for (i=0;i<10;i++){ fprintf(stdout,"Hello "); ft_thread_cooperate(); } exit(0); } void w(void *id) { int i; for (i=0;i<10;i++){ fprintf(stdout,"World!\n"); ft_thread_cooperate(); } exit(0); } int main(void) { ft_scheduler_t sched = ft_scheduler_create(); ft_thread_create(sched,h,NULL,NULL); ft_thread_create(sched,w,NULL,NULL); ft_scheduler_start(sched); pthread_exit (0); //ft_exit(); return 0; } /* result Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! end result */ ft_v1.0/tests/test1.c0100644000374300000260000000121307477072670012046 0ustar fb#include "fthread.h" #include "stdio.h" /* the fifth parameter of ft_thread_create is passed to the function run by the thread */ void pr(void *text) { int i; for (i=0;i<10;i++){ fprintf(stdout,"%s",(char*)text); ft_thread_cooperate(); } exit(0); } int main(void) { ft_scheduler_t sched = ft_scheduler_create (); ft_thread_create (sched,pr,NULL,"Hello "); ft_thread_create (sched,pr,NULL,"World!\n"); ft_scheduler_start(sched); ft_exit(); return 0; } /* result Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! end result */ ft_v1.0/tests/test10.c0100644000374300000260000000155007477072670012132 0ustar fb#include "fthread.h" #include "stdio.h" /* cleanup when stopping a thread */ void pr (void *text) { while (1) { fprintf (stdout,"%s",(char*)text); ft_thread_cooperate (); } } void cleanup (void *args) { fprintf (stdout,"clean up!!!!!!!!\n"); } void control (void *args) { ft_thread_t t = (ft_thread_t)args; ft_thread_cooperate_n (10); ft_scheduler_stop (t); fprintf (stdout,"stop\n"); ft_thread_join (t); fprintf (stdout,"exit\n"); exit(0); } int main (void) { ft_thread_t ft; ft_scheduler_t sched = ft_scheduler_create (); ft = ft_thread_create (sched,pr,cleanup,"*"); if (ft == NULL) { fprintf (stderr,"error!!!\n"); exit (-1); } ft_thread_create (sched,control,NULL,(void*)ft); ft_scheduler_start (sched); ft_exit (); return 0; } /* result ***********stop clean up!!!!!!!! exit end result */ ft_v1.0/tests/test11.c0100644000374300000260000000223207477072670012131 0ustar fb#include "fthread.h" #include #include /* mutual stops */ void run (void *args) { ft_thread_t *t = (ft_thread_t*)args; ft_thread_cooperate_n (3); ft_scheduler_stop (*t); fprintf (stdout,"stopping a thread\n"); while (1) ft_thread_cooperate (); } void cleanup (void *args) { sleep (1); fprintf (stdout,"2 clean up should appear!!!!!!!!\n"); fflush (stdout); } void traceInstants (void *args) { int i = 0; while (1) { fprintf (stdout,"\n>>>>>>>>>>> instant %d ",i++); ft_thread_cooperate (); } } int main (void) { int c, *cell = &c; ft_scheduler_t sched = ft_scheduler_create (); ft_thread_t ft0, ft1; //ft_thread_create (sched,traceInstants,NULL,NULL); ft0 = ft_thread_create (sched,run,cleanup,(void*)&ft1); ft1 = ft_thread_create (sched,run,cleanup,(void*)&ft0); ft_scheduler_start (sched); pthread_join (ft_pthread (ft0),(void**)&cell); pthread_join (ft_pthread (ft1),(void**)&cell); fprintf (stdout,"exit\n"); exit (0); return 0; } /* result stopping a thread stopping a thread 2 clean up should appear!!!!!!!! 2 clean up should appear!!!!!!!! exit end result */ ft_v1.0/tests/test12.c0100644000374300000260000000235507477072670012140 0ustar fb#include "fthread.h" #include "stdio.h" /* suspend/resume */ void run (void *args) { while (1) { fprintf (stdout,"%s",(char*)args); ft_thread_cooperate(); } } void control (void *args) { ft_thread_cooperate_n (3); fprintf (stdout,"suspend "); ft_scheduler_suspend ((ft_thread_t)args); ft_thread_cooperate_n (3); fprintf (stdout,"resume "); ft_scheduler_resume ((ft_thread_t)args); ft_thread_cooperate_n (3); fprintf (stdout,"exit\n"); exit (0); } void traceInstants (void* args) { int i = 0; while (1) { fprintf (stdout,"\n>>>>>>>>>>> instant %d: ",i++); ft_thread_cooperate (); } } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); ft_thread_t ft0; ft_thread_create (sched,traceInstants,NULL,NULL); ft0 = ft_thread_create (sched,run,NULL,(void*)"*"); ft_thread_create (sched,control,NULL,(void*)ft0); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: * >>>>>>>>>>> instant 1: * >>>>>>>>>>> instant 2: * >>>>>>>>>>> instant 3: *suspend >>>>>>>>>>> instant 4: >>>>>>>>>>> instant 5: >>>>>>>>>>> instant 6: resume >>>>>>>>>>> instant 7: * >>>>>>>>>>> instant 8: * >>>>>>>>>>> instant 9: *exit end result */ ft_v1.0/tests/test13.c0100644000374300000260000000226107477072670012135 0ustar fb#include "fthread.h" #include "stdio.h" /* simultaneous suspend/resume; suspend has higher priority */ void run (void *args) { while (1) { fprintf (stdout,"%s",(char*)args); ft_thread_cooperate (); } } void control (void *args) { ft_thread_cooperate_n (3); fprintf (stdout,"suspend "); ft_scheduler_suspend ((ft_thread_t)args); fprintf (stdout,"resume "); ft_scheduler_resume ((ft_thread_t)args); ft_thread_cooperate_n (3); fprintf (stdout,"exit\n"); exit(0); } void traceInstants (void *args) { int i = 0; while (1) { fprintf (stdout,"\n>>>>>>>>>>> instant %d: ",i++); ft_thread_cooperate (); } } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); ft_thread_t ft0; ft_thread_create (sched,traceInstants,NULL,NULL); ft0 = ft_thread_create (sched,run,NULL,(void*)"*"); ft_thread_create (sched,control,NULL,(void*)ft0); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: * >>>>>>>>>>> instant 1: * >>>>>>>>>>> instant 2: * >>>>>>>>>>> instant 3: *suspend resume >>>>>>>>>>> instant 4: >>>>>>>>>>> instant 5: >>>>>>>>>>> instant 6: exit end result */ ft_v1.0/tests/test14.c0100644000374300000260000000256507477072670012145 0ustar fb#include "fthread.h" #include "stdio.h" /* broadcast */ void run (void *args) { while (1) { ft_thread_await ((ft_event_t)args); fprintf (stdout,"received! "); ft_thread_cooperate (); } } void control (void *args) { ft_thread_cooperate_n (3); fprintf (stdout,"generate "); ft_thread_generate ((ft_event_t)args); ft_thread_cooperate_n (3); fprintf (stdout,"broadcast "); ft_scheduler_broadcast ((ft_event_t)args); ft_thread_cooperate_n (3); fprintf (stdout,"exit\n"); exit(0); } void traceInstants (void *args) { int i = 0; while (1) { fprintf (stdout,"\n>>>>>>>>>>> instant %d: ",i++); ft_thread_cooperate (); } } int main (void) { ft_scheduler_t sched = ft_scheduler_create(); ft_event_t go = ft_event_create(sched); if (go == NULL) { fprintf (stderr, "error!!!!\n"); exit (-1); } ft_thread_create (sched,traceInstants,NULL,NULL); ft_thread_create (sched,run,NULL,(void*)go); ft_thread_create (sched,control,NULL,(void*)go); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: >>>>>>>>>>> instant 1: >>>>>>>>>>> instant 2: >>>>>>>>>>> instant 3: generate received! >>>>>>>>>>> instant 4: >>>>>>>>>>> instant 5: >>>>>>>>>>> instant 6: broadcast >>>>>>>>>>> instant 7: received! >>>>>>>>>>> instant 8: >>>>>>>>>>> instant 9: exit end result */ ft_v1.0/tests/test15.c0100644000374300000260000000325707477072670012145 0ustar fb#include "fthread.h" #include "stdio.h" /* generate_value */ void run (void *args) { int v, *cell = &v, **value = &cell; while (1){ ft_thread_await ((ft_event_t)args); ft_thread_get_value ((ft_event_t)args,0,(void**)value); fprintf (stdout,"received %d! ",**value); ft_thread_cooperate (); } } void control (void *args) { int value; ft_thread_cooperate_n (2); value = 12; fprintf (stdout,"generate %d ",value); ft_thread_generate_value ((ft_event_t)args,(void*)&value); ft_thread_cooperate_n (2); value = 22; fprintf (stdout,"generate %d ",value); ft_thread_generate_value ((ft_event_t)args,(void*)&value); ft_thread_cooperate_n (2); value = 32; fprintf (stdout,"generate %d ",value); ft_thread_generate_value ((ft_event_t)args,(void*)&value); ft_thread_cooperate_n (2); fprintf (stdout,"exit\n"); exit (0); } void traceInstants (void *args) { int i = 0; while (1) { fprintf (stdout,"\n>>>>>>>>>>> instant %d: ",i++); ft_thread_cooperate (); } } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); ft_event_t go = ft_event_create (sched); ft_thread_create (sched,traceInstants,NULL,NULL); ft_thread_create (sched,run,NULL,(void*)go); ft_thread_create (sched,control,NULL,(void*)go); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: >>>>>>>>>>> instant 1: >>>>>>>>>>> instant 2: generate 12 received 12! >>>>>>>>>>> instant 3: >>>>>>>>>>> instant 4: generate 22 received 22! >>>>>>>>>>> instant 5: >>>>>>>>>>> instant 6: generate 32 received 32! >>>>>>>>>>> instant 7: >>>>>>>>>>> instant 8: exit end result */ ft_v1.0/tests/test16.c0100644000374300000260000000314407477072670012141 0ustar fb#include "fthread.h" #include "stdio.h" /* generate_value */ void run (void *args) { int v; int *c = &v; int **value = &c; while (1){ int i,res; ft_thread_await ((ft_event_t)args); i=0; while (1){ res = ft_thread_get_value ((ft_event_t)args,i++,(void**)value); if (res != 0) break; fprintf (stdout,"received %d! ",**value); } } } void control (void *args) { int v1,v2; ft_thread_cooperate_n (2); v1 = 12; fprintf (stdout,"generate %d ",v1); ft_thread_generate_value ((ft_event_t)args,(void*)&v1); ft_thread_cooperate_n (1); v1 = 22; fprintf (stdout,"generate %d ",v1); ft_thread_generate_value ((ft_event_t)args,(void*)&v1); v2 = 32; fprintf (stdout,"generate %d ",v2); ft_thread_generate_value ((ft_event_t)args,(void*)&v2); ft_thread_cooperate_n (2); fprintf (stdout,"exit\n"); exit (0); } void traceInstants (void *args) { int i = 0; while (1){ fprintf (stdout,"\n>>>>>>>>>>> instant %d: ",i++); ft_thread_cooperate (); } } int main(void) { ft_scheduler_t sched = ft_scheduler_create (); ft_event_t go = ft_event_create (sched); ft_thread_create (sched,traceInstants,NULL,NULL); ft_thread_create (sched,run,NULL,(void*)go); ft_thread_create (sched,control,NULL,(void*)go); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0: >>>>>>>>>>> instant 1: >>>>>>>>>>> instant 2: generate 12 received 12! >>>>>>>>>>> instant 3: generate 22 generate 32 received 22! received 32! >>>>>>>>>>> instant 4: >>>>>>>>>>> instant 5: exit end result */ ft_v1.0/tests/test17.c0100644000374300000260000000137607477072670012147 0ustar fb#include "fthread.h" #include "stdio.h" /* await_n */ ft_thread_t ft0, ft1; ft_event_t start; void pr (void *text) { int i; ft_thread_await_n (start,100); for (i=0;i<10;i++) { fprintf (stdout,"%s",(char*)text); ft_thread_cooperate (); } } void control (void* args) { ft_thread_join (ft0); exit (0); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); start = ft_event_create (sched); ft1 = ft_thread_create (sched,control,NULL,NULL); ft0 = ft_thread_create (sched,pr,NULL,"Hello World!\n"); ft_scheduler_start (sched); ft_exit (); return 0; } /* result Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! end result */ ft_v1.0/tests/test18.c0100644000374300000260000000151007477072670012136 0ustar fb#include "fthread.h" #include "stdio.h" #include /* join an unlinked thread */ ft_thread_t ft0; /********************************************/ void behav (void *text) { ft_thread_unlink (); usleep (1); fprintf (stdout,"sleep finished\n"); } void control (void *args) { fprintf (stdout,"try to join\n"); ft_thread_join (ft0); fprintf (stdout,"exit\n"); exit (0); } void empty (void *args) { while (1) ft_thread_cooperate (); } /********************************************/ int main (void) { ft_scheduler_t sched = ft_scheduler_create (); ft_thread_create (sched,control,NULL,NULL); ft0 = ft_thread_create (sched,behav,NULL,NULL); ft_thread_create (sched,empty,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result try to join sleep finished exit end result */ ft_v1.0/tests/test19.c0100644000374300000260000000156507477072670012151 0ustar fb#include "fthread.h" #include "stdio.h" #include /* unlink/link */ /********************************************/ void behav (void *args) { ft_scheduler_t s = ft_thread_scheduler (); ft_thread_unlink (); usleep (1); fprintf (stdout,"sleep finished\n"); ft_thread_link (s); if (OK != ft_thread_generate ((ft_event_t)args)) fprintf (stdout,"cannot generate event\n"); } void control (void *args) { ft_thread_await ((ft_event_t)args); fprintf (stdout,"exit\n"); exit (0); } /********************************************/ int main (void) { ft_scheduler_t sched = ft_scheduler_create (); ft_event_t evt = ft_event_create (sched); ft_thread_create (sched,control,NULL,(void*)evt); ft_thread_create (sched,behav,NULL,(void*)evt); ft_scheduler_start (sched); ft_exit (); return 0; } /* result sleep finished exit end result */ ft_v1.0/tests/test2.c0100644000374300000260000000127607477072670012060 0ustar fb#include "fthread.h" #include "stdio.h" /* cooperate_n */ void pr (void *text) { while (1){ fprintf(stdout,"%s",(char*)text); ft_thread_cooperate(); } } /* kill must be static!? */ static void kill (void* args) { ft_thread_cooperate_n(10); exit(0); } int main(void) { ft_scheduler_t sched = ft_scheduler_create (); ft_thread_create (sched,kill,NULL,(void*)10); ft_thread_create (sched,pr,NULL,"Hello "); ft_thread_create (sched,pr,NULL,"World!\n"); ft_scheduler_start (sched); ft_exit (); return 0; } /* result Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! end result */ ft_v1.0/tests/test20.c0100644000374300000260000000174107477072670012135 0ustar fb#include "fthread.h" #include "stdio.h" /* use of locks */ long MAX = (long)1e5; long V1 = 0, V2 = 0; ft_thread_t ft0, ft1; void unlinked (void *arg) { int i; pthread_mutex_t* mutex = arg; ft_thread_unlink (); for (i=0;i /* thread creation */ int i = 10; void behav (void *args) { if (i > 0){ ft_scheduler_t s = (ft_scheduler_t) args; i--; ft_thread_create (s,behav,NULL,s); ft_thread_cooperate (); fprintf (stdout,"new thread %d!\n",i); }else{ fprintf (stdout,"no more thread!\n"); fflush (stdout); exit(0); } } int main(void) { ft_scheduler_t sched = ft_scheduler_create (); ft_thread_create (sched,behav,NULL,sched); ft_scheduler_start (sched); ft_exit (); return 0; } /* result new thread 9! new thread 8! new thread 7! new thread 6! new thread 5! new thread 4! new thread 3! new thread 2! new thread 1! new thread 0! no more thread! end result */ ft_v1.0/tests/test22.c0100644000374300000260000000130207477072670012130 0ustar fb#include "fthread.h" #include "stdio.h" /* thread starting */ /* Thread are started when the OS decided to do so. So, thread actual starting is asynchronous with thread creation */ int i = 0; void countInstants (void *args) { while (1) { i++; ft_thread_cooperate (); } } void f (void *args) { fprintf (stdout,"executed at instant %d\n",i); exit (0); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); ft_thread_create (sched,countInstants,NULL,NULL); ft_scheduler_start (sched); ft_thread_create (sched,f,NULL,NULL); fprintf (stdout,"created at instant %d\n",i); ft_exit (); return 0; } /* result NONDETERMINISTIC end result */ ft_v1.0/tests/test23.c0100644000374300000260000000113307477072670012133 0ustar fb#include "fthread.h" #include "stdio.h" /* use the base pthread */ void* pr (void *text) { int i; for (i=0;i<10;i++) { fprintf (stdout,"%s",(char*)text); } return NULL; } int main(void) { int v, *cell = &v; ft_thread_t th1 = NULL, th2 = NULL; pthread_t pth1, pth2; pth1 = ft_pthread (th1); pth2 = ft_pthread (th2); pthread_create (&pth1,NULL,pr,"Hello "); pthread_create (&pth2,NULL,pr,"World!\n"); pthread_join (pth1,(void**)&cell); pthread_join (pth2,(void**)&cell); fprintf (stdout,"exit\n"); return 0; } /* result NONDETERMINISTIC end result */ ft_v1.0/tests/test24.c0100644000374300000260000000141507477072670012137 0ustar fb#include "fthread.h" #include "stdio.h" /* join the base pthread is possible */ void pr (void *text) { int i; for (i=0;i<10;i++) { fprintf (stdout,"%s",(char*)text); ft_thread_cooperate (); } } int main(void) { int v, *cell = &v; ft_thread_t th1,th2; ft_scheduler_t sched = ft_scheduler_create (); th1 = ft_thread_create (sched,pr,NULL,"Hello "); th2 = ft_thread_create (sched,pr,NULL,"World!\n"); ft_scheduler_start(sched); pthread_join (ft_pthread (th1),(void**)&cell); pthread_join (ft_pthread (th2),(void**)&cell); fprintf (stdout,"exit\n"); exit (0); return 0; } /* result Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! exit end result */ ft_v1.0/tests/test25.c0100644000374300000260000000254707477072670012147 0ustar fb#include "fthread.h" #include "stdio.h" #include /* use of locks */ int v1 = 0, v2 = 0; void unlink_incr (void *args) { int i; ft_thread_unlink (); for (i=0;i<1000000000;i++) { ft_thread_mutex_lock ((pthread_mutex_t*)args); v1++; //usleep (1); v2++; ft_thread_mutex_unlock ((pthread_mutex_t*)args); //fprintf (stdout,"unlink: %d - %d\n",v1,v2); //usleep (1); } } void link_incr (void *args) { int i; for (i=0;i<100;i++) { ft_thread_mutex_lock ((pthread_mutex_t*)args); v1++; ft_thread_cooperate_n (100); v2++; ft_thread_mutex_unlock ((pthread_mutex_t*)args); ft_thread_cooperate (); //fprintf (stdout,"link: %d - %d\n",v1,v2); } } int main (void) { int v, *cell = &v; ft_thread_t th1,th2,th3; ft_scheduler_t sched = ft_scheduler_create (); pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; th1 = ft_thread_create (sched,unlink_incr,NULL,&mutex); th2 = ft_thread_create (sched,link_incr,NULL,&mutex); th3 = ft_thread_create (sched,link_incr,NULL,&mutex); ft_scheduler_start (sched); pthread_join(ft_pthread(th2),(void**)&cell); pthread_join(ft_pthread(th3),(void**)&cell); fprintf (stdout,"values: %d - %d\n",v1,v2); exit (0); return 0; } /* result NONDETERMINISTIC but values should be equal end result */ ft_v1.0/tests/test26.c0100644000374300000260000000143407477072670012142 0ustar fb#include "fthread.h" #include "stdio.h" /* locks owned by a fair thread are automatically released when it terminates */ void take (void *args) { fprintf (stdout,"take lock\n"); ft_thread_mutex_lock ((pthread_mutex_t*)args); fprintf (stdout,"end\n"); } int main (void) { int v, *cell = &v; ft_scheduler_t sched = ft_scheduler_create (); pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; ft_thread_t th1 = ft_thread_create (sched,take,NULL,&mutex); ft_thread_t th2 = ft_thread_create (sched,take,NULL,&mutex); ft_scheduler_start (sched); pthread_join (ft_pthread (th1),(void**)&cell); pthread_join (ft_pthread (th2),(void**)&cell); fprintf (stdout,"exit\n"); exit (0); return 0; } /* result take lock end take lock end exit end result */ ft_v1.0/tests/test27.c0100644000374300000260000000171207477072670012142 0ustar fb#include "fthread.h" #include "stdio.h" #include /* locks owned by a fair thread are automatically released when it is stopped */ ft_thread_t th1,th2; pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; void b1 (void *args) { ft_thread_mutex_lock (&mutex1); ft_thread_mutex_lock (&mutex2); fprintf (stdout,"take locks\n"); while (1) ft_thread_cooperate (); } void b2 (void *args) { ft_thread_cooperate_n (100); ft_scheduler_stop (th1); fprintf (stdout,"thread stopped\n"); ft_thread_mutex_lock (&mutex1); ft_thread_mutex_lock (&mutex2); fprintf (stdout,"take locks\n"); exit (0); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); th1 = ft_thread_create (sched,b1,NULL,NULL); th2 = ft_thread_create (sched,b2,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result take locks thread stopped take locks end result */ ft_v1.0/tests/test28.c0100644000374300000260000000176707477072670012155 0ustar fb#include "fthread.h" #include /* A NOT cooperative thread linked to a scheduler only blocks this scheduler */ ft_scheduler_t sched1, sched2; int i1 = 0, i2 = 0; void f1 (void *args) { while (1) { /* this thread is NOT cooperative !!!! */ } } void f2 (void *args) { ft_thread_cooperate_n (10); fprintf (stdout,"exit at instant (sched1: %d, sched2: %d)\n",i1,i2); exit (0); } void traceInstants (void *args) { int *pi = (int*) args; while (1) { (*pi)++; ft_thread_cooperate (); } } int main (void) { ft_thread_t th1, th2; sched1 = ft_scheduler_create (); sched2 = ft_scheduler_create (); ft_thread_create (sched1,traceInstants,NULL,&i1); ft_thread_create (sched2,traceInstants,NULL,&i2); th1 = ft_thread_create (sched1,f1,NULL,NULL); th2 = ft_thread_create (sched2,f2,NULL,NULL); ft_scheduler_start (sched1); ft_scheduler_start (sched2); ft_exit (); return 0; } /* result exit at instant (sched1: 1, sched2: 11) end result */ ft_v1.0/tests/test29.c0100644000374300000260000000120407477072670012140 0ustar fb#include "fthread.h" #include "stdio.h" /* join with ft_exit */ void exiting (void *args) { ft_thread_cooperate_n (10); fprintf (stdout, "running\n"); ft_exit (); fprintf (stdout, "should not appear!!!!!\n"); } void await_join (void* args) { ft_thread_join ((ft_thread_t)args); fprintf (stdout, "exit\n"); exit (0); } int main (void) { ft_thread_t ft1; ft_scheduler_t sched = ft_scheduler_create (); ft1 = ft_thread_create (sched,exiting,NULL,NULL); ft_thread_create (sched,await_join,NULL,(void*)ft1); ft_scheduler_start (sched); ft_exit (); return 0; } /* result running exit end result */ ft_v1.0/tests/test3.c0100644000374300000260000000141307477072670012052 0ustar fb#include "fthread.h" #include "stdio.h" /* join */ ft_thread_t ft0, ft1, ft2; void pr (void *text) { int i; for (i=0;i<10;i++) { fprintf(stdout,"%s",(char*)text); ft_thread_cooperate (); } } /* kill must be static!? */ static void kill (void* args) { ft_thread_join (ft0); ft_thread_join (ft1); exit (0); } int main(void) { ft_scheduler_t sched = ft_scheduler_create (); ft2 = ft_thread_create (sched,kill,NULL,NULL); ft0 = ft_thread_create (sched,pr,NULL,"Hello "); ft1 = ft_thread_create (sched,pr,NULL,"World!\n"); ft_scheduler_start (sched); ft_exit (); return 0; } /* result Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! end result */ ft_v1.0/tests/test30.c0100644000374300000260000000126607477072670012140 0ustar fb#include "fthread.h" #include "stdio.h" /* join with an unlinked thread executing ft_exit */ void exiting (void *args) { ft_thread_cooperate_n (10); ft_thread_unlink (); fprintf (stdout, "running\n"); ft_exit (); fprintf (stdout, "should not appear!!!!!\n"); } void await_join (void* args) { ft_thread_join ((ft_thread_t)args); fprintf (stdout, "exit\n"); exit (0); } int main (void) { ft_thread_t ft1; ft_scheduler_t sched = ft_scheduler_create(); ft1 = ft_thread_create (sched,exiting,NULL,NULL); ft_thread_create (sched,await_join,NULL,(void*)ft1); ft_scheduler_start (sched); ft_exit (); return 0; } /* result running exit end result */ ft_v1.0/tests/test31.c0100644000374300000260000000145107477072670012135 0ustar fb#include "fthread.h" #include "stdio.h" /* cleanup executed only when the stopped thread was not finished */ void behav (void *args) { ft_thread_cooperate_n (3); fprintf (stdout,"thread finished: no cleanup should appear\n"); } void run (void *args) { ft_thread_cooperate_n (3); ft_scheduler_stop ((ft_thread_t)args); ft_thread_cooperate_n (6); fprintf (stdout,"exit\n"); exit (0); } void cleanup (void *args) { fprintf (stdout,"clean up!!!!!!!!\n"); } int main(void) { ft_thread_t ft1; ft_scheduler_t sched = ft_scheduler_create (); ft1 = ft_thread_create (sched,behav,cleanup,NULL); ft_thread_create (sched,run,NULL,(void*)ft1); ft_scheduler_start (sched); ft_exit (); return 0; } /* result thread finished: no cleanup should appear exit end result */ ft_v1.0/tests/test32.c0100644000374300000260000000242507477072670012140 0ustar fb#include "fthread.h" #include "stdio.h" /* cleanup is also called when stopping a suspended thread */ void behav (void *args) { while (1) { fprintf (stdout,"*"); ft_thread_cooperate (); } } void run (void *args) { ft_thread_t t = (ft_thread_t)args; ft_thread_cooperate_n (2); fprintf (stdout,"order to suspend thread\n"); ft_scheduler_suspend (t); ft_thread_cooperate_n (3); fprintf (stdout,"order to stop thread\n"); ft_scheduler_stop (t); ft_thread_cooperate_n (6); ft_thread_join (t); fprintf (stdout,"exit\n"); exit (0); } void cleanup (void *args) { fprintf (stdout,"clean up!!!!!!!!\n"); fflush (stdout); } void traceInstants (void *args) { int i = 0; while (1) { fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i++); fflush (stdout); ft_thread_cooperate (); } } /*******************************/ int main (void) { ft_thread_t ft1; ft_scheduler_t sched = ft_scheduler_create (); ft1 = ft_thread_create (sched,behav,cleanup,NULL); ft_thread_create (sched,run,NULL,(void*)ft1); //ft_thread_create (sched,traceInstants,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result ***order to suspend thread order to stop thread clean up!!!!!!!! exit end result */ ft_v1.0/tests/test33.c0100644000374300000260000000214007477072670012133 0ustar fb#include "fthread.h" #include "stdio.h" #include /* large number of threads waiting for events */ #define CYCLES 100000 #define EVENT_NUM 20 // must be less than the max number of threads in the system void counter (void *args) { int count = 0; int i; fprintf (stdout, "start counting\n"); for (i=0;i /* large number of threads waiting for the same event */ #define CYCLES 100000 #define EVENT_NUM 20 // must be less than the max number of threads in the system void counter (void *args) { int count = 0; int i; //ft_scheduler_t s = ft_thread_scheduler (); //ft_thread_unlink (); fprintf (stdout, "start counting\n"); for (i=0;i /* stop a thread awaiting an event */ ft_event_t evt; ft_thread_t th; void killer (void *args) { ft_thread_cooperate_n (10); fprintf (stdout, "stop!\n"); ft_scheduler_stop (th); ft_thread_cooperate_n (10); fprintf (stdout, "generate!\n"); ft_thread_generate (evt); ft_thread_cooperate_n (10); fprintf (stdout, "exit!\n"); exit (0); } void waiter (void *args) { ft_thread_await (evt); fprintf (stdout, "received!\n"); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); evt = ft_event_create (sched); th = ft_thread_create (sched,waiter,NULL,NULL); ft_thread_create (sched,killer,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result stop! generate! exit! end result */ ft_v1.0/tests/test36.c0100644000374300000260000000147607477072670012151 0ustar fb#include "fthread.h" #include "stdio.h" #include /* await n times takes exactly n instants */ ft_event_t evt; ft_thread_t th; void awaiter (void *args) { ft_thread_await_n (evt,10); fprintf (stdout, "timeout!\n"); exit (0); } int i = 1; void trace_instant (void *args) { while (1) { fprintf (stdout, "\ninstant %d: ",i); i++; ft_thread_cooperate (); } } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); evt = ft_event_create (sched); ft_thread_create (sched,trace_instant,NULL,NULL); ft_thread_create (sched,awaiter,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result instant 1: instant 2: instant 3: instant 4: instant 5: instant 6: instant 7: instant 8: instant 9: instant 10: instant 11: timeout! end result */ ft_v1.0/tests/test37.c0100644000374300000260000000126707477072670012150 0ustar fb#include "fthread.h" #include "stdio.h" #include /* awaiting 0 times */ ft_event_t evt; ft_thread_t th; void awaiter (void *args) { ft_thread_await_n (evt,0); fprintf (stdout, "timeout!\n"); exit (0); } int i = 1; void trace_instant (void *args) { while (1) { fprintf (stdout, "\ninstant %d: ",i); i++; ft_thread_cooperate (); } } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); evt = ft_event_create (sched); ft_thread_create (sched,trace_instant,NULL,NULL); ft_thread_create (sched,awaiter,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result instant 1: timeout! end result */ ft_v1.0/tests/test38.c0100644000374300000260000000120307477072670012137 0ustar fb#include "fthread.h" #include "stdio.h" #include /* cooperating 0 times */ ft_thread_t th; void awaiter (void *args) { ft_thread_cooperate_n (0); fprintf (stdout, "exit!\n"); exit (0); } int i = 1; void trace_instant (void *args) { while (1) { fprintf (stdout, "\ninstant %d: ",i); i++; ft_thread_cooperate (); } } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); ft_thread_create (sched,trace_instant,NULL,NULL); ft_thread_create (sched,awaiter,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result instant 1: exit! end result */ ft_v1.0/tests/test39.c0100644000374300000260000000176207477072670012152 0ustar fb#include "fthread.h" #include "stdio.h" /* cooperating n times takes exactly n instants */ ft_thread_t th; void awaiter (void *args) { int i; for (i=0;i<5;i++) { fprintf (stdout, "[cooperate %d times ",i); ft_thread_cooperate_n (i); fprintf (stdout, "] "); } fprintf (stdout, "exit!\n"); exit (0); } int i = 1; void trace_instant (void *args) { while (1) { fprintf (stdout, "\ninstant %d: ",i); i++; ft_thread_cooperate (); } } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); ft_thread_create (sched,trace_instant,NULL,NULL); ft_thread_create (sched,awaiter,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result instant 1: [cooperate 0 times ] [cooperate 1 times instant 2: ] [cooperate 2 times instant 3: instant 4: ] [cooperate 3 times instant 5: instant 6: instant 7: ] [cooperate 4 times instant 8: instant 9: instant 10: instant 11: ] exit! end result */ ft_v1.0/tests/test4.c0100644000374300000260000000160607477072670012057 0ustar fb#include "fthread.h" #include "stdio.h" /* join_n */ ft_thread_t ft0, ft1, ft2; void pr (void *text) { while (1) { fprintf(stdout,"%s",(char*)text); ft_thread_cooperate (); } } /* kill must be static!? */ static void kill (void* args) { ft_thread_join_n (ft0,10); ft_thread_join_n (ft1,10); exit (0); } int main(void) { ft_scheduler_t sched = ft_scheduler_create (); ft2 = ft_thread_create (sched,kill,NULL,NULL); ft0 = ft_thread_create (sched,pr,NULL,"Hello "); ft1 = ft_thread_create (sched,pr,NULL,"World!\n"); ft_scheduler_start (sched); ft_exit (); return 0; } /* result Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! end result */ ft_v1.0/tests/test40.c0100644000374300000260000000236107477072670012136 0ustar fb#include "fthread.h" #include "stdio.h" /* await_n : received, then timeout */ ft_event_t evt; void one (void) { int res = ft_thread_await_n (evt,10); if (res == OK) fprintf (stdout, "event received! "); if (res == ETIMEOUT) fprintf (stdout, "timeout! "); } void awaiter (void *args) { one (); ft_thread_cooperate (); one (); fprintf (stdout, "exit!\n"); exit (0); } void trace_instant (void *args) { int i = 1; while (1) { fprintf (stdout, "\ninstant %d: ",i); i++; ft_thread_cooperate (); } } void generator (void *args) { ft_thread_cooperate_n (3); fprintf (stdout, "event generated! "); ft_thread_generate (evt); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); evt = ft_event_create (sched); ft_thread_create (sched,trace_instant,NULL,NULL); ft_thread_create (sched,awaiter,NULL,NULL); ft_thread_create (sched,generator,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result instant 1: instant 2: instant 3: instant 4: event generated! event received! instant 5: instant 6: instant 7: instant 8: instant 9: instant 10: instant 11: instant 12: instant 13: instant 14: instant 15: timeout! exit! end result */ ft_v1.0/tests/test41.c0100644000374300000260000000243507477072670012141 0ustar fb#include "fthread.h" #include "stdio.h" /* await_n then cooperate */ ft_event_t evt; void awaiter (void *args) { int res = ft_thread_await_n (evt,10); if (res == OK) fprintf (stdout, "event received! "); if (res == ETIMEOUT) fprintf (stdout, "timeout! "); ft_thread_cooperate_n (20); fprintf (stdout, "exit!\n"); exit (0); } void trace_instant (void *args) { int i = 1; while (1) { fprintf (stdout, "\ninstant %d: ",i); i++; ft_thread_cooperate (); } } void generator (void *args) { ft_thread_cooperate_n (3); fprintf (stdout, "event generated! "); ft_thread_generate (evt); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); evt = ft_event_create (sched); ft_thread_create (sched,trace_instant,NULL,NULL); ft_thread_create (sched,awaiter,NULL,NULL); ft_thread_create (sched,generator,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result instant 1: instant 2: instant 3: instant 4: event generated! event received! instant 5: instant 6: instant 7: instant 8: instant 9: instant 10: instant 11: instant 12: instant 13: instant 14: instant 15: instant 16: instant 17: instant 18: instant 19: instant 20: instant 21: instant 22: instant 23: instant 24: exit! end result */ ft_v1.0/tests/test42.c0100644000374300000260000000256707477072670012150 0ustar fb#include "fthread.h" #include "stdio.h" /* await_n : received, then received another time */ ft_event_t evt; void one (void) { int res = ft_thread_await_n (evt,10); if (res == OK) fprintf (stdout, "event received! "); if (res == ETIMEOUT) fprintf (stdout, "timeout! "); } void awaiter (void *args) { one (); ft_thread_cooperate (); one (); fprintf (stdout, "exit!\n"); exit (0); } void trace_instant (void *args) { int i = 1; while (1) { fprintf (stdout, "\ninstant %d: ",i); i++; ft_thread_cooperate (); } } void generator (void *args) { ft_thread_cooperate_n (3); fprintf (stdout, "event generated! "); ft_thread_generate (evt); ft_thread_cooperate_n (10); fprintf (stdout, "event generated! "); ft_thread_generate (evt); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); evt = ft_event_create (sched); ft_thread_create (sched,trace_instant,NULL,NULL); ft_thread_create (sched,awaiter,NULL,NULL); ft_thread_create (sched,generator,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result instant 1: instant 2: instant 3: instant 4: event generated! event received! instant 5: instant 6: instant 7: instant 8: instant 9: instant 10: instant 11: instant 12: instant 13: instant 14: event generated! event received! exit! end result */ ft_v1.0/tests/test43.c0100644000374300000260000000266207477072670012145 0ustar fb#include "fthread.h" #include "stdio.h" /* await_n : received, then received another time */ ft_event_t evt1, evt2; void one (ft_event_t evt) { int res = ft_thread_await_n (evt,10); if (res == OK) fprintf (stdout, "event received! "); if (res == ETIMEOUT) fprintf (stdout, "timeout! "); } void awaiter (void *args) { one (evt1); ft_thread_cooperate (); one (evt2); fprintf (stdout, "exit!\n"); exit (0); } void trace_instant (void *args) { int i = 1; while (1) { fprintf (stdout, "\ninstant %d: ",i); i++; ft_thread_cooperate (); } } void generator (void *args) { ft_thread_cooperate_n (3); fprintf (stdout, "evt1 generated! "); ft_thread_generate (evt1); ft_thread_cooperate_n (10); fprintf (stdout, "evt2 generated! "); ft_thread_generate (evt2); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); evt1 = ft_event_create (sched); evt2 = ft_event_create (sched); ft_thread_create (sched,trace_instant,NULL,NULL); ft_thread_create (sched,awaiter,NULL,NULL); ft_thread_create (sched,generator,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result instant 1: instant 2: instant 3: instant 4: evt1 generated! event received! instant 5: instant 6: instant 7: instant 8: instant 9: instant 10: instant 11: instant 12: instant 13: instant 14: evt2 generated! event received! exit! end result */ ft_v1.0/tests/test44.c0100644000374300000260000000256707477072670012152 0ustar fb#include "fthread.h" #include "stdio.h" /* await_n : received, then received another time */ ft_event_t evt; void one (void) { int res = ft_thread_await_n (evt,10); if (res == OK) fprintf (stdout, "event received! "); if (res == ETIMEOUT) fprintf (stdout, "timeout! "); } void awaiter (void *args) { one (); ft_thread_cooperate (); one (); fprintf (stdout, "exit!\n"); exit (0); } void trace_instant (void *args) { int i = 1; while (1) { fprintf (stdout, "\ninstant %d: ",i); i++; ft_thread_cooperate (); } } void generator (void *args) { ft_thread_cooperate_n (3); fprintf (stdout, "event generated! "); ft_thread_generate (evt); ft_thread_cooperate_n (10); fprintf (stdout, "event generated! "); ft_thread_generate (evt); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); evt = ft_event_create (sched); ft_thread_create (sched,trace_instant,NULL,NULL); ft_thread_create (sched,awaiter,NULL,NULL); ft_thread_create (sched,generator,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result instant 1: instant 2: instant 3: instant 4: event generated! event received! instant 5: instant 6: instant 7: instant 8: instant 9: instant 10: instant 11: instant 12: instant 13: instant 14: event generated! event received! exit! end result */ ft_v1.0/tests/test45.c0100644000374300000260000000112307477072670012136 0ustar fb#include "fthread.h" #include "stdio.h" #include /* */ #define CYCLES 1000000 void waiter (void *args) { int i; i=0; fprintf (stdout, "start waiting\n"); //for (i=0;i /* efficiency of await_n implementation */ #define CYCLES 100000 #define NUMBER 100 // less than the max number of threads void waiter (void *args) { ft_thread_await_n ((ft_event_t)args,CYCLES); fprintf (stdout, "end waiting\n"); exit (0); } int main (void) { int i; ft_scheduler_t sched = ft_scheduler_create (); for (i=0;i>>>>>>>>>> instant %d: ",i++); ft_thread_cooperate (); } } int main(void) { ft_scheduler_t sched = ft_scheduler_create(); event1 = ft_event_create (sched); event2 = ft_event_create (sched); //ft_thread_create (sched,traceInstants,NULL,NULL); ft_thread_create(sched,waiter1,NULL,NULL); ft_thread_create(sched,waiter2,NULL,NULL); ft_scheduler_start(sched); ft_exit(); return 0; } /* result exit! end result */ ft_v1.0/tests/test48.c0100644000374300000260000000062007477072670012142 0ustar fb#include "fthread.h" #include "stdio.h" /* only one thread which waits for a future instant */ void waiter (void *id) { ft_thread_cooperate_n (10); fprintf (stdout,"exit!\n"); exit (0); } int main(void) { ft_scheduler_t sched = ft_scheduler_create(); ft_thread_create(sched,waiter,NULL,NULL); ft_scheduler_start(sched); ft_exit(); return 0; } /* result exit! end result */ ft_v1.0/tests/test49.c0100644000374300000260000000125307477072670012146 0ustar fb#include "fthread.h" #include "stdio.h" #include ft_event_t event; void waiter (void *id) { ft_thread_await (event); fprintf (stdout,"exit!\n"); exit (0); } void traceInstants (void *args) { int i = 0; while (1) { fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i++); ft_thread_cooperate (); } } int main(void) { ft_scheduler_t sched = ft_scheduler_create(); event = ft_event_create (sched); //ft_thread_create (sched,traceInstants,NULL,NULL); ft_thread_create(sched,waiter,NULL,NULL); ft_scheduler_start(sched); sleep (1); ft_scheduler_broadcast (event); ft_exit(); return 0; } /* result exit! end result */ ft_v1.0/tests/test5.c0100644000374300000260000000157707477072670012067 0ustar fb#include "fthread.h" #include "stdio.h" /* await */ ft_thread_t ft0, ft1, ft2; ft_event_t start; void pr (void *text) { int i; ft_thread_await (start); for (i=0;i<10;i++) { fprintf(stdout,"%s",(char*)text); ft_thread_cooperate (); } } void control (void* args) { ft_thread_cooperate_n (5); ft_thread_generate (start); ft_thread_join (ft0); ft_thread_join (ft1); exit(0); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); start = ft_event_create (sched); ft2 = ft_thread_create (sched,control,NULL,NULL); ft0 = ft_thread_create (sched,pr,NULL,"Hello "); ft1 = ft_thread_create (sched,pr,NULL,"World!\n"); ft_scheduler_start (sched); ft_exit (); return 0; } /* result Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! end result */ ft_v1.0/tests/test50.c0100644000374300000260000000335107477072670012137 0ustar fb#include "fthread.h" #include "stdio.h" /* cleanup is also called when stopping a suspended thread */ ft_thread_t ft1,ft2; void behav (void *args) { while (1) { fprintf (stdout,"%s ",(char*)args); ft_thread_cooperate (); } } void killer (void *args) { ft_thread_cooperate_n (10); fprintf (stdout,"stop ft1 "); ft_scheduler_stop (ft1); fprintf (stdout,"stop ft2 "); ft_scheduler_stop (ft2); ft_thread_cooperate_n (10); fprintf (stdout,"exit\n"); exit (0); } void cleanup (void *args) { fprintf (stdout,"\nclean up of %s!!!!!!!!\n",(char*)args); } void traceInstants (void *args) { int i = 0; while (1) { fprintf(stdout,"\n>>>>>>>>>>> instant %d: ",i++); fflush (stdout); ft_thread_cooperate (); } } /*******************************/ int main (void) { ft_scheduler_t sched = ft_scheduler_create (); ft1 = ft_thread_create (sched,behav,cleanup,"1"); ft2 = ft_thread_create (sched,behav,cleanup,"2"); ft_thread_create (sched,killer,NULL,NULL); ft_thread_create (sched,traceInstants,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result 1 2 >>>>>>>>>>> instant 0: 1 2 >>>>>>>>>>> instant 1: 1 2 >>>>>>>>>>> instant 2: 1 2 >>>>>>>>>>> instant 3: 1 2 >>>>>>>>>>> instant 4: 1 2 >>>>>>>>>>> instant 5: 1 2 >>>>>>>>>>> instant 6: 1 2 >>>>>>>>>>> instant 7: 1 2 >>>>>>>>>>> instant 8: 1 2 >>>>>>>>>>> instant 9: 1 2 stop ft1 stop ft2 >>>>>>>>>>> instant 10: clean up of 1!!!!!!!! clean up of 2!!!!!!!! >>>>>>>>>>> instant 11: >>>>>>>>>>> instant 12: >>>>>>>>>>> instant 13: >>>>>>>>>>> instant 14: >>>>>>>>>>> instant 15: >>>>>>>>>>> instant 16: >>>>>>>>>>> instant 17: >>>>>>>>>>> instant 18: >>>>>>>>>>> instant 19: exit end result */ ft_v1.0/tests/test6.c0100644000374300000260000000163307477072670012061 0ustar fb#include "fthread.h" #include "stdio.h" /* instantaneous dialog */ ft_thread_t ft0, ft1, ft2; ft_event_t e1, e2, e3; void r1 (void *text) { ft_thread_await (e1); ft_thread_generate (e2); ft_thread_await (e3); fprintf (stdout,"e3 received!\n"); } void r2 (void *text) { ft_thread_generate (e1); ft_thread_await (e2); ft_thread_generate (e3); fprintf (stdout,"e3 generated!\n"); } void control (void* args) { ft_thread_join (ft0); ft_thread_join (ft1); exit (0); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); e1 = ft_event_create(sched); e2 = ft_event_create(sched); e3 = ft_event_create(sched); ft2 = ft_thread_create (sched,control,NULL,NULL); ft1 = ft_thread_create (sched,r2,NULL,NULL); ft0 = ft_thread_create (sched,r1,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } /* result e3 generated! e3 received! end result */ ft_v1.0/tests/test7.c0100644000374300000260000000234107477072670012057 0ustar fb#include "fthread.h" #include "stdio.h" #include /* events are broadcast */ int max = 10; ft_scheduler_t sched; ft_event_t evt; ft_thread_t *table; void fonc (void *args) { fprintf (stdout,"start waiting!!!!!\n"); ft_thread_await (evt); fprintf (stdout,"received!!!!!\n"); } void control (void* args) { int i; ft_thread_cooperate_n (3); fprintf (stdout,"generated!!!!!\n"); ft_thread_generate (evt); for(i=0; i /* events are instantaneously broadcast */ int max = 10; ft_scheduler_t sched; ft_event_t evt; ft_thread_t *table; void fonc (void *args) { fprintf (stdout,"start waiting!!!!!\n"); ft_thread_await (evt); fprintf (stdout,"received!!!!!\n"); } void control (void* args) { int i; ft_thread_cooperate_n (3); fprintf (stdout,"generated!!!!!\n"); ft_thread_generate (evt); for(i=0; i>>>>>>>>>> instant %d\n",i++); ft_thread_cooperate (); } } int main (void) { int i; sched = ft_scheduler_create (); evt = ft_event_create (sched); table = (ft_thread_t*)malloc (max*sizeof (ft_thread_t)); ft_thread_create (sched,traceInstants,NULL,NULL); for (i=0; i>>>>>>>>>> instant 0 start waiting!!!!! start waiting!!!!! start waiting!!!!! start waiting!!!!! start waiting!!!!! start waiting!!!!! start waiting!!!!! start waiting!!!!! start waiting!!!!! start waiting!!!!! >>>>>>>>>>> instant 1 >>>>>>>>>>> instant 2 >>>>>>>>>>> instant 3 generated!!!!! received!!!!! received!!!!! received!!!!! received!!!!! received!!!!! received!!!!! received!!!!! received!!!!! received!!!!! received!!!!! >>>>>>>>>>> instant 4 end result */ ft_v1.0/tests/test9.c0100644000374300000260000000216207477072670012062 0ustar fb#include "fthread.h" #include "stdio.h" /* stop */ void pr (void *text) { while (1) { fprintf(stdout,"%s",(char*)text); ft_thread_cooperate (); } } void control (void* args) { ft_thread_cooperate_n (10); ft_scheduler_stop ((ft_thread_t)args); fprintf (stdout,"stop\n"); ft_thread_join ((ft_thread_t)args); fprintf (stdout,"exit\n"); exit (0); } void traceInstants () { int i = 0; while (1) { fprintf (stdout,">>>>>>>>>>> instant %d\n",i++); ft_thread_cooperate (); } } int main (void) { ft_thread_t ft; ft_scheduler_t sched = ft_scheduler_create (); ft_thread_create (sched,traceInstants,NULL,NULL); ft = ft_thread_create (sched,pr,NULL,"*"); ft_thread_create (sched,control,NULL,(void*)ft); ft_scheduler_start (sched); ft_exit (); return 0; } /* result >>>>>>>>>>> instant 0 *>>>>>>>>>>> instant 1 *>>>>>>>>>>> instant 2 *>>>>>>>>>>> instant 3 *>>>>>>>>>>> instant 4 *>>>>>>>>>>> instant 5 *>>>>>>>>>>> instant 6 *>>>>>>>>>>> instant 7 *>>>>>>>>>>> instant 8 *>>>>>>>>>>> instant 9 *>>>>>>>>>>> instant 10 *stop >>>>>>>>>>> instant 11 exit end result */ ft_v1.0/examples/0040755000374300000260000000000007477072670011324 5ustar fbft_v1.0/examples/dialogc.c0100644000374300000260000000302407477072670013066 0ustar fb#include #include #include /*************************************/ pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t e1 = PTHREAD_COND_INITIALIZER; pthread_cond_t e2 = PTHREAD_COND_INITIALIZER; /*************************************/ void* behav1 (void *args) { //usleep(1); // OK with sleep pthread_mutex_lock (&mutex1); pthread_cond_broadcast (&e1); fprintf (stdout,"broadcast e1\n"); pthread_mutex_unlock (&mutex1); pthread_mutex_lock (&mutex2); fprintf (stdout,"wait e2\n"); pthread_cond_wait (&e2,&mutex2); fprintf (stdout,"receive e2\n"); pthread_mutex_unlock (&mutex2); fprintf (stdout,"end of behav1\n"); return NULL; } void* behav2 (void *args) { pthread_mutex_lock (&mutex1); fprintf (stdout,"wait e1\n"); pthread_cond_wait (&e1,&mutex1); fprintf (stdout,"receive e1\n"); pthread_mutex_unlock (&mutex1); pthread_mutex_lock (&mutex2); pthread_cond_broadcast (&e2); fprintf (stdout,"broadcast e2\n"); pthread_mutex_unlock (&mutex2); fprintf (stdout,"end of behav2\n"); return NULL; } /*************************************/ int main(void) { int c, *cell = &c; pthread_t th1, th2; pthread_create (&th1,NULL,behav1,NULL); pthread_create (&th2,NULL,behav2,NULL); pthread_join(th1,(void**)&cell); pthread_join(th2,(void**)&cell); fprintf (stdout,"exit\n"); exit (0); } /* Does not always work (terminate)... */ ft_v1.0/examples/dialogft.c0100644000374300000260000000236607477072670013265 0ustar fb#include "fthread.h" #include #include /*************************************/ ft_event_t e1, e2; /*************************************/ void behav1 (void *args) { ft_thread_generate (e1); fprintf (stdout,"broadcast e1\n"); fprintf (stdout,"wait e2\n"); ft_thread_await (e2); fprintf (stdout,"receive e2\n"); fprintf (stdout,"end of behav1\n"); } void behav2 (void *args) { fprintf (stdout,"wait e1\n"); ft_thread_await (e1); fprintf (stdout,"receive e1\n"); ft_thread_generate (e2); fprintf (stdout,"broadcast e2\n"); fprintf (stdout,"end of behav2\n"); } /*************************************/ int main(void) { int c, *cell = &c; ft_thread_t th1, th2; ft_scheduler_t sched = ft_scheduler_create (); e1 = ft_event_create (sched); e2 = ft_event_create (sched); th1 = ft_thread_create (sched,behav1,NULL,NULL); th2 = ft_thread_create (sched,behav2,NULL,NULL); ft_scheduler_start (sched); pthread_join (ft_pthread (th1),(void**)&cell); pthread_join (ft_pthread (th2),(void**)&cell); fprintf (stdout,"exit\n"); exit (0); } /* broadcast e1 wait e2 wait e1 receive e1 broadcast e2 end of behav2 receive e2 end of behav1 exit */ ft_v1.0/examples/hello.c0100644000374300000260000000071607477072670012574 0ustar fb#include "fthread.h" #include "stdio.h" void h (void *id) { while (1) { fprintf (stderr,"Hello "); ft_thread_cooperate (); } } void w (void *id) { while (1) { fprintf (stderr,"World!\n"); ft_thread_cooperate (); } } int main(void) { ft_scheduler_t sched = ft_scheduler_create (); ft_thread_create (sched,h,NULL,NULL); ft_thread_create (sched,w,NULL,NULL); ft_scheduler_start (sched); ft_exit (); return 0; } ft_v1.0/examples/makefile0100644000374300000260000000044207477072670013021 0ustar fbCC = gcc -Wall -O3 -D_REENTRANT -I ../include -L ../lib LIBS = -lfthread -lpthread ############ C code to executable code ##################### .c : $(CC) $< $(LIBS) a.out #################### all: echo "type: make x" #################### clean: rm -f *~ a.out ####################ft_v1.0/examples/nbread.c0100644000374300000260000000164207477072670012723 0ustar fb#include "fthread.h" #include #include #include /*********************************************/ ssize_t ft_thread_read (int fd,void *buf,size_t count) { ft_scheduler_t sched = ft_thread_scheduler (); ssize_t res; ft_thread_unlink (); res = read (fd,buf,count); ft_thread_link (sched); return res; } /*********************************************/ void reading_behav (void* args) { int max = (int)args; char *buf = (char*)malloc (max+1); ssize_t res; fprintf (stderr,"enter %d characters:\n",max); res = ft_thread_read (0,buf,max); if (-1 == res) fprintf (stderr,"error\n"); buf[res] = 0; fprintf (stderr,"read %d: <%s>\n",res,buf); exit (0); } int main (void) { ft_scheduler_t sched = ft_scheduler_create (); ft_thread_create (sched,reading_behav,NULL,(void*)5); ft_scheduler_start (sched); ft_exit(); return 0; } ft_v1.0/examples/ndhello.c0100644000374300000260000000105007477072670013106 0ustar fb#include "fthread.h" #include "stdio.h" void h (void *id) { while (1) { fprintf (stderr,"Hello "); ft_thread_cooperate (); } } void w (void *id) { while (1) { fprintf (stderr,"World!\n"); ft_thread_cooperate (); } } int main (void) { ft_scheduler_t sched1 = ft_scheduler_create (); ft_scheduler_t sched2 = ft_scheduler_create (); ft_thread_create (sched1,h,NULL,NULL); ft_thread_create (sched2,w,NULL,NULL); ft_scheduler_start (sched1); ft_scheduler_start (sched2); ft_exit (); return 0; } ft_v1.0/examples/printer.c0100644000374300000260000000356407477072670013160 0ustar fb#include "fthread.h" #include "stdio.h" #include /*******************/ void *printer = NULL; int printer_available; int initialization_in_progress; ft_event_t printer_ready; ft_scheduler_t spooler; void start_spooler () { printer_available = 0; initialization_in_progress = 0; spooler = ft_scheduler_create (); printer_ready = ft_event_create (spooler); ft_scheduler_start (spooler); } void initialize_printer () { fprintf(stderr,"start printer initialization\n"); initialization_in_progress = 1; ft_thread_unlink (); sleep (4); printer = &fprintf; ft_thread_link (spooler); printer_available = 1; fprintf (stderr,"printer initialized!\n"); } void print (char *text) { printer_available = 0; ft_thread_unlink (); fprintf (stderr,text); ft_thread_link (spooler); printer_available = 1; } void lpr (char *text) { ft_scheduler_t s = ft_thread_scheduler(); ft_thread_unlink (); ft_thread_link (spooler); if (printer == NULL && !initialization_in_progress){ initialize_printer (); } while (1) { if (printer_available) { print (text); ft_thread_generate (printer_ready); ft_thread_unlink (); ft_thread_link (s); return; } ft_thread_await (printer_ready); if (!printer_available) ft_thread_cooperate (); } } /*******************/ void behav (void *text) { while (1) { lpr (text); } } void trace (void *text) { while (1) { fprintf (stderr,"%s",(char*)text); ft_thread_cooperate (); } } /*******************/ int main (void) { ft_scheduler_t sched = ft_scheduler_create (); start_spooler (); ft_thread_create (sched,behav,NULL,"0"); ft_thread_create (sched,behav,NULL,"1"); ft_thread_create (sched,behav,NULL,"2"); ft_thread_create (sched,trace,NULL,"*"); ft_scheduler_start (sched); ft_exit (); return 0; } ft_v1.0/examples/prodcons.h0100644000374300000260000000036007477072670013320 0ustar fb#define PRODUCED 5000 // number of produced values #define FILE_SIZE 20 // size of files #define MAX_THREADS 5 // number of threads #define PROCESSING 1000000 // processing delay #define PRINT(s,v) fprintf (stderr,s,v) ft_v1.0/examples/prodcons1.h0100644000374300000260000000040307477072670013377 0ustar fb#define PRODUCED 100 // number of produced values #define FILE_SIZE 10 // size of files #define MAX_THREADS 20 // number of threads #define PROCESSING 100000 // processing delay #define CYCLES 1000 #define PRINT(s,v) //fprintf (stderr,s,v) ft_v1.0/examples/prodcons1c.c0100644000374300000260000000506407477072670013545 0ustar fb#include #include #include #include #include #include "prodcons1.h" /*************************************/ typedef struct cell { int value; struct cell *next; } *cell; typedef struct list { int length; cell first; cell last; } *list; list add (int v, list l) { cell c = (cell) malloc (sizeof (struct cell)); c->value = v; c->next = NULL; if (l == NULL){ l = (list) malloc (sizeof (struct list)); l->length = 0; l->first = c; }else{ l->last->next = c; } l->length++; l->last = c; return l; } void put (int v,list *l) { (*l) = add (v,*l); } int get (list *l) { int res; list file = *l; if (l == NULL) { fprintf (stderr, "get error!\n"); return 0; } res = file->first->value; file->length--; if (file->last == file->first){ file = NULL; }else{ file->first = file->first->next; } return res; } int size (list l) { if (l==NULL) return 0; return l->length; } /*************************************/ list file = NULL; pthread_mutex_t file_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t new_elem = PTHREAD_COND_INITIALIZER; int processed = 0; /*************************************/ void process_value (int v) { int i,j; for (i=0;i 0){ int res = get (&file); pthread_mutex_unlock(&file_mutex); if (res == CYCLES){ PRINT("result: %d\n",res); processed++; if (processed == PRODUCED) exit (0); }else{ process_value(res); } pthread_mutex_lock(&file_mutex); }else{ pthread_cond_wait (&new_elem,&file_mutex); } } return NULL; } void* produce (void *args) { int v = 0; while (v < PRODUCED) { pthread_mutex_lock (&file_mutex); if (size(file) < FILE_SIZE){ put (0,&file); PRINT("%d produced\n",0); pthread_cond_signal (&new_elem); v++; pthread_mutex_unlock (&file_mutex); }else{ pthread_mutex_unlock(&file_mutex); sched_yield(); } } return NULL; } /*************************************/ int main(void) { int i; pthread_t producer; pthread_t thread_array[MAX_THREADS]; for (i=0; i #include #include #include "prodcons1.h" /*************************************/ typedef struct cell { int value; struct cell *next; } *cell; typedef struct list { int length; cell first; cell last; } *list; list add (int v, list l) { cell c = (cell) malloc (sizeof (struct cell)); c->value = v; c->next = NULL; if (l == NULL){ l = (list) malloc (sizeof (struct list)); l->length = 0; l->first = c; }else{ l->last->next = c; } l->length++; l->last = c; return l; } void put (int v,list *l) { (*l) = add (v,*l); } int get (list *l) { int res; list file = *l; if (l == NULL) { fprintf (stderr, "get error!\n"); return 0; } res = file->first->value; file->length--; if (file->last == file->first){ file = NULL; }else{ file->first = file->first->next; } return res; } int size (list l) { if (l==NULL) return 0; return l->length; } /*************************************/ list file = NULL; ft_scheduler_t file_sched; ft_event_t new_elem; int processed = 0; /*************************************/ void process_value (int v) { int i,j; ft_thread_unlink (); for (i=0;i 0){ int res = get (&file); if (res == CYCLES) { PRINT("result: %d\n",res); processed++; if (processed == PRODUCED) exit (0); }else{ process_value(res); } }else{ ft_thread_await (new_elem); if (size (file) == 0) ft_thread_cooperate (); } } } void produce (void *args) { int v = 0; while (v < PRODUCED) { if (size(file) < FILE_SIZE) { put (0,&file); PRINT("%d produced\n",0); ft_thread_generate (new_elem); v++; } ft_thread_cooperate (); } } /*************************************/ int main (void) { int i; ft_thread_t thread_array[MAX_THREADS]; file_sched = ft_scheduler_create (); new_elem = ft_event_create (file_sched); for (i=0; i #include #include #include #include #include "prodcons.h" /*************************************/ typedef struct cell { int value; struct cell *next; } *cell; typedef struct list { int length; cell first; cell last; } *list; list add (int v, list l) { cell c = (cell) malloc (sizeof (struct cell)); c->value = v; c->next = NULL; if (l == NULL){ l = (list) malloc (sizeof (struct list)); l->length = 0; l->first = c; }else{ l->last->next = c; } l->length++; l->last = c; return l; } void put (int v,list *l) { (*l) = add (v,*l); } int get (list *l) { int res; list file = *l; if (l == NULL) { fprintf (stderr, "get error!\n"); return 0; } res = file->first->value; file->length--; if (file->last == file->first){ file = NULL; }else{ file->first = file->first->next; } return res; } int size (list l) { if (l==NULL) return 0; return l->length; } /*************************************/ list in = NULL, out = NULL; pthread_mutex_t producer_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t consumer_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t new_input = PTHREAD_COND_INITIALIZER; pthread_cond_t new_output = PTHREAD_COND_INITIALIZER; /*************************************/ void process_value (int v) { int i,j; for (i=0;i 0){ int v = get(&in); pthread_mutex_unlock(&producer_mutex); process_value(v); pthread_mutex_lock(&producer_mutex); }else{ pthread_cond_wait (&new_input,&producer_mutex); } } return NULL; } void* produce (void *args) { int v = 0; while (v < PRODUCED) { pthread_mutex_lock(&producer_mutex); if (size(in) < FILE_SIZE){ put (v,&in); PRINT("%d produced\n",v); pthread_cond_signal (&new_input); v++; pthread_mutex_unlock (&producer_mutex); }else{ pthread_mutex_unlock(&producer_mutex); sched_yield(); } } return NULL; } void* consume (void *args) { int v = 0; while (v < PRODUCED) { pthread_mutex_lock(&consumer_mutex); if (size(out) > 0){ int res = get (&out); PRINT("consume %d\n",res); v++; }else{ pthread_cond_wait (&new_output,&consumer_mutex); } pthread_mutex_unlock(&consumer_mutex); } exit (0); return NULL; } /*************************************/ int main(void) { int i; pthread_t producer,consumer; pthread_t thread_array[MAX_THREADS]; for (i=0; i #include #include #include "prodcons.h" /*************************************/ typedef struct cell { int value; struct cell *next; } *cell; typedef struct file { int length; cell first; cell last; } *file; file add (int v, file l) { cell c = (cell) malloc (sizeof (struct cell)); c->value = v; c->next = NULL; if (l == NULL){ l = (file) malloc (sizeof (struct file)); l->length = 0; l->first = c; }else{ l->last->next = c; } l->length++; l->last = c; return l; } void put (int v,file *l) { (*l) = add (v,*l); } int get (file *l) { int res; file f = *l; if (l == NULL) { fprintf (stderr, "get error!\n"); return 0; } res = f->first->value; f->length--; if (f->last == f->first){ f = NULL; }else{ f->first = f->first->next; } return res; } int size (file l) { if (l==NULL) return 0; return l->length; } /*************************************/ file in = NULL, out = NULL; ft_scheduler_t in_sched, out_sched; ft_event_t new_input, new_output; /*************************************/ void process_value (int v) { int i,j; ft_thread_unlink(); for (i=0;i 0){ process_value(get(&in)); }else{ ft_thread_await (new_input); if (size (in) == 0) ft_thread_cooperate (); } } } void produce (void *args) { int v = 0; while (v < PRODUCED) { if (size(in) < FILE_SIZE){ put (v,&in); PRINT("%d produced\n",v); ft_thread_generate (new_input); v++; } ft_thread_cooperate (); } } void consume (void *args) { int v = 0; while (v < PRODUCED) { if (size(out) > 0){ int res = get (&out); PRINT("consume %d\n",res); v++; }else{ ft_thread_await (new_output); if (size(out) == 0) ft_thread_cooperate (); } } exit(0); } /*************************************/ int main(void) { int i; ft_thread_t thread_array[MAX_THREADS]; in_sched = ft_scheduler_create (); out_sched = ft_scheduler_create (); new_input = ft_event_create (in_sched); new_output = ft_event_create (out_sched); for (i=0; i #include /*************************************/ ft_scheduler_t sched; ft_event_t answer; ft_thread_t th, request, timer; /*************************************/ void first_attempt (void *args) { fprintf (stdout, "try connection with server1\n"); ft_thread_cooperate_n (5000); fprintf (stdout, "success of connection with server1\n"); ft_thread_generate (answer); ft_scheduler_stop ((ft_thread_t)args); } void timer1_behav (void *args) { int n = 100; fprintf (stdout, "start timer for %d s\n",n); ft_thread_cooperate_n (n); fprintf (stdout, "end timer for %d s\n",n); fprintf (stdout, "stop connection with server1\n"); ft_scheduler_stop ((ft_thread_t)args); } /*************************************/ void second_attempt (void *args) { fprintf (stdout, "try connection with server2\n"); ft_thread_cooperate_n (4000); fprintf (stdout, "success of connection with server2\n"); ft_thread_generate (answer); ft_thread_cooperate (); ft_scheduler_stop ((ft_thread_t)args); ft_thread_generate (answer); } void timer2_behav (void *args) { int n = 6000; fprintf (stdout, "start timer for %d s\n",n); ft_thread_cooperate_n (n); fprintf (stdout, "end timer for %d s\n",n); ft_scheduler_stop ((ft_thread_t)args); fprintf (stdout, "stop connection with server2\n"); fprintf (stdout, "no server available\n"); ft_thread_generate (answer); } /*************************************/ void handler (void *args) { request = ft_thread_create (sched,second_attempt,NULL,timer); timer = ft_thread_create (sched,timer2_behav,NULL,request); } void behav (void *args) { request = ft_thread_create (sched,first_attempt,handler,timer); timer = ft_thread_create (sched,timer1_behav,NULL,request); ft_thread_await (answer); fprintf (stdout,"end of behav\n"); exit (0); } /*************************************/ int main(void) { sched = ft_scheduler_create (); answer = ft_event_create (sched); th = ft_thread_create (sched,behav,NULL,NULL); ft_scheduler_start(sched); ft_exit (); return 0; } ft_v1.0/README0100644000374300000260000000120407477072670010360 0ustar fbTo compile the library: 1) go in the directory src and type make. This should produce the library libfthread.a. However, one assumes that gcc, make, ar, and ranlib are available. If it is not the case, you should edit the makefile to set correctly the corresponding variables. 2) type make install to install the file fthread.h in ../include and libfthread.a in ../lib. If these two items are to be installed in an other place, edit the makefile and change the two variables INCL_DIR and LIB_DIR. 3) you can verify that the installation is correct by running the tests in the directory tests, or the examples in the directory examples.