diff -NaurbB rtlinux-3.2-pre1.old/doc/Configure.help rtlinux-3.2-pre1/doc/Configure.help --- rtlinux-3.2-pre1.old/doc/Configure.help 2002-10-30 16:57:11.000000000 +0100 +++ rtlinux-3.2-pre1/doc/Configure.help 2003-07-17 10:52:44.000000000 +0200 @@ -89,3 +89,78 @@ to dramatically reduce scheduling jitter. You need a 2.4.X kernel with CONFIG_SMP enabled for this option to work. +POSIX Signals +_RTL_POSIX_SIGNALS + A POSIX signal is the software equivalent of an interrupt or + exception occurrence. Say Y here if you want to make use of + the POSIX interface to signals. This allows you to send signals + (RTL_SIGUSR1,RTL_SIGUSR2 and from signal RTL_SIGRTMIN to RTL_SIGRTMAX) + to threads (pthread_kill), blocking signals (pthread_sigmask), + suspend a thread waiting for a signal to arrive (sigsuspend) and + install signal handlers, among other things. Signals are in + determinated cases a good interprocess communication mechanism. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -NaurbB rtlinux-3.2-pre1.old/examples/bug/Makefile rtlinux-3.2-pre1/examples/bug/Makefile --- rtlinux-3.2-pre1.old/examples/bug/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/bug/Makefile 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,31 @@ +all: sched_bug.o mutex_bug.o + +include ../../rtl.mk +include $(RTL_DIR)/Rules.make + +ifneq ($(ARCH),mips) +LIBGCC := $(shell $(CC) -print-libgcc-file-name) +else +LIBGCC = libgcc.o +libgcc.o: mips/libgcc2.c + $(CC) $(CFLAGS) -DCROSS_COMPILE -DIN_GCC -I./include -DIN_LIBGCC2 -D__GCC_FLOAT_NOT_NEEDED -I. -c -DL_muldi3 mips/libgcc2.c -o libgcc.o +endif + +LDFLAGS=-d + +sched_bug.o: sched_bug.c + $(CC) ${INCLUDE} ${CFLAGS} -c sched_bug.c -g -o sched_bug.o + +mutex_bug.o: mutex_bug.c + $(CC) ${INCLUDE} ${CFLAGS} -c mutex_bug.c -g -o mutex_bug.o + +clean: + rm -f *.o + + + + + + + + diff -NaurbB rtlinux-3.2-pre1.old/examples/bug/mutex_bug.c rtlinux-3.2-pre1/examples/bug/mutex_bug.c --- rtlinux-3.2-pre1.old/examples/bug/mutex_bug.c 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/bug/mutex_bug.c 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,104 @@ +/* + * POSIX.1 Signals + * + * Written by J. Vidal + * Copyright (C) Dec, 2002 OCERA Consortium. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2. + * + * Simple program showing a nasty mutex bug when setting + * t->do_abort=0 on do_signal. + * + */ + +#include +#include +#include + +static pthread_t mutex_owner, blocked_thread; +static pthread_mutex_t mut; + +static void *mutex_owner_routine(void *arg) +{ + struct sched_param p; + int err=0,i=0; + + p . sched_priority =1; + pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); + + rtl_printf("MUTEX OWNER. Just before adquiring the mutex.\n"); + pthread_mutex_lock(&mut); + rtl_printf(" \n\n MUTEX OWNER - Mutual exclusion code.\n"); + rtl_printf("MUTEX_OWNER - Testing mutexes --> sending signals RTL_SIGNAL_SUSPEND & RTL_SIGNAL_WAKEUP\n\n"); + // wait for the other task to get blocked. + usleep(1000); + + err=pthread_wakeup_np(blocked_thread); + rtl_printf("pthread_wakeup_np(thread[blocked_thread]) returns %d\n",err); + err=pthread_suspend_np(blocked_thread); + rtl_printf("pthread_suspend_np(blocked_thread) returns %d\n",err); + err=pthread_wakeup_np(blocked_thread); + rtl_printf("pthread_wakeup_np(thread[blocked_thread]) returns %d\n",err); + + rtl_printf("MUTEX OWNER. BEFORE pthread_mutex_unlock \n"); + err=pthread_mutex_unlock(&mut); + rtl_printf("MUTEX OWNER. pthread_mutex_unlock returned %d. errno %d\n",err,errno); + + rtl_printf("MUTEX OWNER about to end \n"); + return (void *)err; +} + +static void *blocked_thread_routine(void *arg) +{ + int err=0; + struct sched_param p; + + p . sched_priority =1; + pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); + + + rtl_printf("BLOCKED THREAD. Just before adquiring the mutex.\n"); + pthread_mutex_lock(&mut); + rtl_printf(" \n\n BLOCKED THREAD - Mutual exclusion code.\n"); + rtl_printf("BLOCKED THREAD. BEFORE pthread_mutex_unlock \n"); + err=pthread_mutex_unlock(&mut); + rtl_printf("BLOCKED THREAD. pthread_mutex_unlock returned %d. errno %d\n",err,errno); + + rtl_printf("BLOCKED THREAD about to end \n"); + return (void *)err; +} + +int init_module(void) { + pthread_attr_t attr; + pthread_mutexattr_t mutattr; + + pthread_mutexattr_init(&mutattr); + /* pthread_mutexattr_settype(&mutattr,PTHREAD_MUTEX_SPINLOCK_NP); */ + + pthread_mutex_init(&mut,&mutattr); + + pthread_attr_init(&attr); + // Threads creation. + pthread_create (&mutex_owner, &attr, mutex_owner_routine,(void *) 0); + pthread_create (&blocked_thread, &attr, blocked_thread_routine,(void *) 0); + + return 0; +} + +void cleanup_module(void) { + void *retval; + + + pthread_join (mutex_owner, &retval); + rtl_printf("pthread_join on MUTEX OWNER returned %d\n", (int) retval); + pthread_join (blocked_thread, &retval); + rtl_printf("pthread_join on BLOCKED THREAD returned %d\n", (int) retval); + + + //pthread_delete_np(thread[i]); + + pthread_mutex_destroy(&mut); + +} diff -NaurbB rtlinux-3.2-pre1.old/examples/bug/README rtlinux-3.2-pre1/examples/bug/README --- rtlinux-3.2-pre1.old/examples/bug/README 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/bug/README 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,74 @@ +/* + * POSIX.1 Signals + * + * Written by J. Vidal + * Copyright (C) Dec, 2002 OCERA Consortium. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2. + * + * RTLinux found bugs. + * + */ + + +Scheduler BUG 6-11-02: + + The RTLinux scheduler for version 3.1 is re-entrant when it wants to +suspend a thread. The procedure is the following. When it wants to +suspend a thread different from pthread_self() (with pthread_suspend_np()) +it sends a signal to that thread ( RTL_SIGNAL_SUSPEND). Then the scheduler +decides to give the CPU for that thread so it has a pending signal. But +the handler for that signal marks the thread as suspended and calls the +scheduler again. +If the process is repeated, as in the following example (sched_bug.c), +what we are doing is to push calls to the scheduler in the threads stack. +If we are suspended and nobody wakes up us (in a mutex, calling +pthread_suspend_np,etc ..) the stack becomes exhausted in a finite time. +In version 3.0 the scheduler wasn't reentrant and this error doesn't occur. +A good test is to change the stack size and observe that the iterates +proportionaly to the stack increment.We have the same problem with user +signals handlers. + +Proposed solution: +The solution was to return to the scheduler policy of version 3.0, being +non re-entrant. + +Mutex BUG 4-12-02: + + Well, the fact is that do_signal when receives the signal RTL_SIGNAL_SUSPENDS sets +t->abort to zero. So, when it calls do_abort(t) it has no effect. + In our example, blocked thread was blocked on a mutex. Meantime mutex owner thread +is sending signal to it (pthread_wakeup_nppthread_suspend_np, pthread_wakeup_np). + What happens is the following: + 1.- The blocked gets blocked on the mutex (calling rtl_wait_sleep on the +pthread_mutex_lock loop), and it is queued in the mutex wait queue. + 2.- At this point, mutex owner sends the following signals: + 2.1.- RTL_SIGNAL_WAKEUP: blocked thread takes the CPU to manage it. Then it calls to +do_abort and rtl_wait_abort takes it out of the mutex wait queue. Then it loops again and +calls rtl_wait_sleep and it is queued on mutex wait queue. This time the behaviour is the +spected. + 2.2.- Next blocked thread receives the signal RTL_SIGNAL_SUSPEND which sets +t->abort to zero, marks blocked thread suspended and calls the scheduler. + 2.3.- Finally, blocked thread receives the RTL_SIGNAL_WAKEUP again. But this time +when do_abort is called, it has no effect (so RTL_SIGNAL_SUSPEND set its to zero). So blocked +thread isn't removed from mutex wait queue. But the code follows (rtl_wait_sleep returns) +looping at pthread_mutex_lock loop, calling rtl_wait_sleep again. This function queues +blocked thread in mutex wait queue which was queued allready (well, not exactly since +the struct queued was local to rtl_wait_sleep, but this struct reamins when the stack is +decreme). At this time mutex wait queue contains the following: head -> thread1 -> head. + And here is the bug we got a double linked wait queue where the head and the tail +are pointing the same waiter (blocked thread ). + 4.- When thread 0 calls pthread_mutex_unlock and runs the mutex wait queue to wake up blocked threads it runs an infinite loop and the user lost the machine control (so linux never enters). + + +Proposed solution: + Possibly, setting do_abort to zero when managing RTL_SIGNAL_SUSPEND is for future compatibility or a simple mistake. Now abort field of thread's structure is only used for mutexes and semaphores. One solution is to not set to zero and execute do_abort when managing the RTL_SIGNAL_SUPEND signal. + + + + + + + diff -NaurbB rtlinux-3.2-pre1.old/examples/bug/sched_bug.c rtlinux-3.2-pre1/examples/bug/sched_bug.c --- rtlinux-3.2-pre1.old/examples/bug/sched_bug.c 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/bug/sched_bug.c 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,74 @@ +/* + * POSIX.1 Signals + * + * Written by J. Vidal + * Copyright (C) Dec, 2002 OCERA Consortium. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2. + * + * Simple program showing stack overflow when sending RTL_SIGNAL_SUSPEND + * signal. J. Vidal (OCERA) + * + */ + +#include +#include +#include + +#define NTASKS 2 +#define MAXINT 0x7fffffff +pthread_t thread[NTASKS]; + +void * start_routine(void *arg) +{ + struct sched_param p; + int ret=0,i=0,param=(unsigned) arg; + long long period=10*1000*1000; + + p . sched_priority = NTASKS -param; + pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); + + if (param==0){ + pthread_make_periodic_np (pthread_self(), gethrtime(),period ); + + while (i++ to continue" + @read junk + -rmmod sound + -rmmod rt_process + -rmmod frank_module + (cd ../../../; scripts/rmrtl) + @echo "Now insert the fifo and scheduler" + @echo "Type to continue" + @read junk + (cd ../../../; scripts/insrtl) + @echo "Now start the real-time tasks module" + @echo "Type to continue" + @read junk + @insmod sig_condvar.o + @sleep 5 + @echo "Now let's stop the application" + @echo "Type to finish" + @read junk + @rmmod sig_condvar + +include ../../../Rules.make diff -NaurbB rtlinux-3.2-pre1.old/examples/signals/cond_var/sig_condvar.c rtlinux-3.2-pre1/examples/signals/cond_var/sig_condvar.c --- rtlinux-3.2-pre1.old/examples/signals/cond_var/sig_condvar.c 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/signals/cond_var/sig_condvar.c 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,120 @@ +/* + * Added user signals to condition variable test, + * Dec, 2002 Josep Vidal (OCERA) + */ + +#include +#include +#include + +static pthread_t thread; +static pthread_mutex_t mutex /* = PTHREAD_MUTEX_INITIALIZER */; +static pthread_cond_t cond; +static int timed=1; +MODULE_PARM(timed,"i"); + +void sig_handler(int sig_rec){ + + rtl_printf("I'm RT-thread, really blocked on a condition variable ...\n"); + rtl_printf("but signals handlers are executed regardless being blocked in a condition variable\n"); + rtl_printf("After finishing handler execution for signal:%d, I will remain suspended\n",sig_rec); +} + +static void * start_routine(void *arg) +{ int ret; + hrtime_t t; + hrtime_t t2; + struct sigaction sa; + rtl_sigset_t mask; + + struct sched_param p; + p . sched_priority = 1; + pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); + + sa.sa_handler=sig_handler; + + rtl_sigfillset(&mask); + rtl_sigdelset(&mask,RTL_SIGRTMIN); + pthread_sigmask(SIG_SETMASK,&mask,NULL); + + if ((ret=sigaction(RTL_SIGRTMIN,&sa,NULL))<0 ){ + rtl_printf("sigaction(%d,&sa,NULL) FAILING, ret:%d.\n",RTL_SIGRTMIN,ret); + } + + rtl_printf("RTLinux thread starts on CPU%d\n", rtl_getcpuid()); + if (timed) { + rtl_printf("RT-thread: about to pthread_cond_timedwait\n"); + t = clock_gethrtime(CLOCK_REALTIME); + + pthread_mutex_lock (&mutex); + ret = pthread_cond_timedwait (&cond, &mutex, hrt2ts(t + 2000000)); + pthread_mutex_unlock (&mutex); + + t2 = clock_gethrtime(CLOCK_REALTIME); + + rtl_printf("RT-thread: pthread_cond_timedwait returned %d (%d ns elapsed)\n", ret, (unsigned) (t2 - t)); + } + + + rtl_printf("RT-thread: about to pthread_cond_wait\n"); + t = clock_gethrtime(CLOCK_REALTIME); + rtl_printf("RT-thread: about to kill itself with RTL_SIGRTMIN\n"); + ret=pthread_kill(pthread_self(),RTL_SIGRTMIN); + rtl_printf("RT-thread: pthread_kill returned %d\n",ret); + pthread_mutex_lock (&mutex); + ret = pthread_cond_wait (&cond, &mutex); + pthread_mutex_unlock (&mutex); + + t2 = clock_gethrtime(CLOCK_REALTIME); + + rtl_printf("RT-thread: pthread_cond_wait returned %d (%d ns elapsed)\n", ret, (unsigned) (t2 - t)); + + return (void *) 35; +} + + +int init_module(void) +{ + int ret; + hrtime_t t; + int sleep = 500000000; + pthread_attr_t attr; + + rtl_printf("RTLinux condvar test starts on CPU%d\n", rtl_getcpuid()); + pthread_attr_init (&attr); + /* try to run the thread on another CPU */ + if (rtl_cpu_exists(!rtl_getcpuid())) { + pthread_attr_setcpu_np(&attr, !rtl_getcpuid()); + } + + pthread_mutex_init (&mutex, NULL); + pthread_cond_init (&cond, NULL); + + ret = pthread_create (&thread, &attr, start_routine, 0); + if (ret) { + rtl_printf("failed to create a thread\n"); + return ret; + } + + rtl_printf("Linux thread is about to busy-wait for %d ns\n", sleep); + t = gethrtime(); + while (gethrtime() < t + sleep); + + rtl_printf("Linux thread is about to signal the condition\n"); + pthread_mutex_lock (&mutex); + ret = pthread_cond_signal (&cond); + pthread_mutex_unlock (&mutex); + rtl_printf("Linux thread: pthread_cond_signal returned %d\n", ret); + + return 0; +} + + +void cleanup_module(void) +{ + void *retval; + pthread_cancel (thread); + pthread_join (thread, &retval); +/* rtl_printf("RTLinux mutex: joined thread returned %d\n", (int) retval); */ + pthread_mutex_destroy (&mutex); +} diff -NaurbB rtlinux-3.2-pre1.old/examples/signals/hello/hello.c rtlinux-3.2-pre1/examples/signals/hello/hello.c --- rtlinux-3.2-pre1.old/examples/signals/hello/hello.c 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/signals/hello/hello.c 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,81 @@ +/* + * POSIX.1 Signals test program + * + * Written by J. Vidal + * Copyright (C) Dec, 2002 OCERA Consortium. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2. + * + * Simple test program implementing the "Hello world" program from a + * signal handler. + * + */ + +#include +#include + +#define MAX_TASKS 2 +#define MY_SIGNAL RTL_SIGUSR2 +static pthread_t thread[MAX_TASKS]; + +static void signal_handler(int sig){ + int i; + + for (i=0;i<2;i++) rtl_printf(">--------------------------------------->\n"); + rtl_printf("Hello world! Signal handler called for signal:%d\n",sig); + for (i=0;i<2;i++) rtl_printf("<---------------------------------------<\n"); + +} + +static void * start_routine(void *arg) +{ int i=0,err=0,signal; + struct sched_param p; + struct sigaction sa; + rtl_sigset_t set; + + p . sched_priority = 1; + pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); + + signal=MY_SIGNAL+(unsigned) arg; + rtl_sigfillset(&set); + rtl_sigdelset(&set,signal); + pthread_sigmask(SIG_SETMASK,&set,NULL); + + sa.sa_handler=signal_handler; + sa.sa_mask=0; + sa.sa_flags=0; + sa.sa_focus=0; + + if ((err=sigaction(signal,&sa,NULL))<0 ) + rtl_printf("sigaction(%d,&sa,NULL) FAILING, err:%d, errno:%d.\n",signal,err,errno); + + pthread_make_periodic_np (pthread_self(), gethrtime(), (long long)250*1000*1000+ (long long)250*1000*1000*(unsigned) arg); + + rtl_printf("I'm here; my arg is %x iter:%d\n",(unsigned) arg,i++); + rtl_printf("When i mod 5 -> pthread_kill(pthread_self(),%d)\n",signal); + + while (i<=40) { + pthread_wait_np (); + if (!(i%5)) pthread_kill(pthread_self(),signal); + rtl_printf("I'm here; my arg is %x iter:%d\n",(unsigned) arg,i++); + } + + rtl_printf("\n\n\n THREAD %d about to end\n\n\n",(unsigned) arg); + return 0; +} + +int init_module(void) { + int i,err=0; + for (i=0;i to continue" + @read junk + -rmmod sound + -rmmod rt_process + -rmmod frank_module + (cd ../../../; scripts/rmrtl) + @echo "Now insert the fifo and scheduler" + @echo "Type to continue" + @read junk + (cd ../../../; scripts/insrtl) + @echo "Now start the real-time tasks module" + @echo "Type to continue" + @read junk + @insmod hello.o + @sleep 3 + @echo "Now let's stop the application" + @echo "Type to finish" + @read junk + @rmmod hello + +include ../../../Rules.make diff -NaurbB rtlinux-3.2-pre1.old/examples/signals/ign_signals/ign_signals.c rtlinux-3.2-pre1/examples/signals/ign_signals/ign_signals.c --- rtlinux-3.2-pre1.old/examples/signals/ign_signals/ign_signals.c 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/signals/ign_signals/ign_signals.c 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,135 @@ +/* + * POSIX.1 Signals test program + * + * Written by J. Vidal + * Copyright (C) Dec, 2002 OCERA Consortium. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2. + * + * In this test a master sends signals to all its slaves. + * Only odd threads should get delivered generated signals. + * So the others threads have installed the default handler or SIG_IGN. + * + */ + +#include +#include + +#define SIGRTMIN RTL_SIGRTMIN + +#define NTASKS 8 +#define ONEMILISEC (long long)1000*1000 +static pthread_t thread[NTASKS]; +long long start_time=0; + +static void send_signals(void){ + static int count=0; + int i=0; + int target_thread_no=0; + + rtl_printf("\n\n\nI am the master & I'm just sending signals to the rest of threads iter:%d.\n",count++); + rtl_printf("Only odd threads should execute the handler and wakeup\n"); + rtl_printf("The other threads are installing the default handler or RTL_SIG_IGN\n\n\n"); + + // Wake up the rest of threads + for (i=1 ;imagic == RTL_THREAD_MAGIC) + pthread_kill(thread[target_thread_no],SIGRTMIN+i); + else + rtl_printf("thread:%d not a valid thread.\n",target_thread_no); + } +} + + +static void signal_handler(int sig){ + rtl_printf("I am a slave thread number:%d executing the handler for signal:%d \n",sig-SIGRTMIN,sig); +} + +static void *start_routine(void *arg) +{ + struct sched_param p; + struct sigaction sa; + int signal; + int err; + long period; + rtl_sigset_t set; + int param=(unsigned) arg; + + rtl_sigfillset(&set); + pthread_sigmask(SIG_BLOCK,&set,NULL); + + p . sched_priority =param; + pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); + + period=(long)2*100*ONEMILISEC; + signal=SIGRTMIN+param; + + if (param){ + if (param % 2) + sa.sa_handler=signal_handler; + else{ + if (param!=NTASKS-1) + sa.sa_handler=SIG_IGN; + else + sa.sa_handler=SIG_DFL; + + } + + sa.sa_mask=0; + sa.sa_flags=0; + + if ((err=sigaction(signal,&sa,NULL))<0 ){ + rtl_printf("sigaction(signal,&sa,NULL) FAILING, err:%d.\n",signal,err); + } + } + + // only one task is periodic. The others are woken up by signals + if (param == 0) { + pthread_make_periodic_np (pthread_self(), start_time ,period ); + + while (1) { + pthread_wait_np(); + send_signals(); + } + } else { + + rtl_sigdelset(&set,signal); + + while (1){ + sigsuspend(&set); + rtl_printf("Slave thread nr:%d. Just wasting time\n",param); + if (!(param % 2)) { + rtl_printf("TEST FAILED!!!!!!!!!! An ignored signal has waken up me!!!!!!!!\n"); + } + } + } + + return 0; +} + +int init_module(void) { + int i; + + start_time=1000*ONEMILISEC; + + // Threads creation. + for (i=0;i to continue" + @read junk + -rmmod sound + -rmmod rt_process + -rmmod frank_module + (cd ../../../; scripts/rmrtl) + @echo "Now insert the fifo and scheduler" + @echo "Type to continue" + @read junk + (cd ../../../; scripts/insrtl) + @echo "Now start the real-time tasks module" + @echo "Type to continue" + @read junk + @insmod ign_signals.o + @echo "Running real-time application for ten seconds!" + @sleep 10 + @echo "Now let's stop the application" + @echo "Type to finish" + @read junk + @rmmod ign_signals + +include ../../../Rules.make diff -NaurbB rtlinux-3.2-pre1.old/examples/signals/mutex/Makefile rtlinux-3.2-pre1/examples/signals/mutex/Makefile --- rtlinux-3.2-pre1.old/examples/signals/mutex/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/signals/mutex/Makefile 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,41 @@ +all: sig_mutex.o sig_timedmutex.o + +include ../../../rtl.mk +clean: + rm -f *.o + +help: + @echo "/**************************************************************/" + @echo "/**************************************************************/" + @echo "/* In this program, various threads are blocked on a mutex. */" + @echo "/* While they are blocked on the mutex, the master threads */" + @echo "/* sends signals to them. At this point blocked threads */" + @echo "/* must execute the signal handler and remain blocked. */" + @echo "/* There is also, a version for timed waits on mutexes. */" + @echo "/**************************************************************/" + @echo "/**************************************************************/" + +test: all help + @echo "First we remove any existing rtl-modules" + @echo "You may see error warnings from \"make\" - ignore them" + @echo "Type to continue" + @read junk + -rmmod sound + -rmmod rt_process + -rmmod frank_module + (cd ../../../; scripts/rmrtl) + @echo "Now insert the fifo and scheduler" + @echo "Type to continue" + @read junk + (cd ../../../; scripts/insrtl) + @echo "Now start the real-time tasks module" + @echo "Type to continue" + @read junk + @insmod sig_mutex.o + @sleep 4 + @echo "Now let's stop the application" + @echo "Type to finish" + @read junk + @rmmod sig_mutex + +include ../../../Rules.make diff -NaurbB rtlinux-3.2-pre1.old/examples/signals/mutex/sig_mutex.c rtlinux-3.2-pre1/examples/signals/mutex/sig_mutex.c --- rtlinux-3.2-pre1.old/examples/signals/mutex/sig_mutex.c 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/signals/mutex/sig_mutex.c 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,133 @@ +/* + * Added user signals to mutex test, + * Dec, 2002 Josep Vidal (OCERA) + */ + +#include +#include +#include +#define NTASKS 3 +#define ITERS 2 +static pthread_t threads[NTASKS]; + +static pthread_mutex_t mutex /* = PTHREAD_MUTEX_INITIALIZER */; + +void my_sig_handler(int sig_rec){ + int thread_no; + + thread_no=sig_rec-RTL_SIGRTMIN; + rtl_printf("I'm thread %d, really blocked on a mutex...\n",thread_no); + rtl_printf("but signals handlers are executed regardless being blocked on a mutex\n"); + rtl_printf("After finishing handler execution for signal:%d, I will remain blocked on the mutex\n",sig_rec); + +} + +static void * start_routine(void *arg) +{ + int ret,i=0,j,signal; + hrtime_t t; + hrtime_t t2; + int sleep = 500000000; + int nthread = (int) arg; + struct sigaction sa; + rtl_sigset_t mask; + + struct sched_param p; + p . sched_priority = nthread; + pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); + + + // Block all signals except the ones you want to receive. + if (nthread){ + sa.sa_handler=my_sig_handler; + sa.sa_mask=0; + sa.sa_flags=0; + + rtl_sigfillset(&mask); + signal=RTL_SIGRTMIN+nthread; + rtl_sigdelset(&mask,signal); + pthread_sigmask(SIG_SETMASK,&mask,NULL); + + if ((ret=sigaction(signal,&sa,NULL))<0 ){ + rtl_printf("sigaction(%d,&sa,NULL) FAILING, ret:%d.\n",signal,ret); + } + } + + rtl_printf("thread %d starts on CPU%d\n", nthread, rtl_getcpuid()); + ret = pthread_mutex_trylock(&mutex); + rtl_printf ("thread %d: pthread_mutex_trylock returned %d\n", nthread, ret); + + if (ret != 0) { + rtl_printf("thread %d: about to pthread_mutex_lock\n", nthread); + t = gethrtime(); + ret = pthread_mutex_lock (&mutex); + t2 = gethrtime(); + rtl_printf("thread %d: pthread_mutex_lock returned %d (%d ns elapsed)\n", nthread, ret, (unsigned) (t2 - t)); + } + + rtl_printf("thread %d is about to sleep for %d ns\n", nthread, sleep); + while (i++ < ITERS){ + nanosleep (hrt2ts(sleep), NULL); + /* + Send all programmed signals to all threads but the sender. + Only the threads which has that signal unblocked will receive it. + Also only the signal which has programmed + a handler to that signal will execute it. + */ + if (!nthread){ + rtl_printf("thread %d testing mutexes in iter %d\n",nthread,i); + for (i=RTL_SIGRTMIN+1;i<(RTL_SIGRTMIN+NTASKS);i++) + for (j=1;j (OCERA) + */ + +#include +#include +#include +#define ITERS 1 +#define NTASKS 2 +static pthread_t thread[NTASKS]; + +static pthread_mutex_t mutex /* = PTHREAD_MUTEX_INITIALIZER */; +static int count=0; + + +void sig_hdl(int sig){ + + rtl_printf("Hi, I am thread %d, really blocked on a timed mutex\n",sig - RTL_SIGUSR1); + rtl_printf("But signal handlers are executed regardless being blocked on a mutex\n"); + rtl_printf("After finishing the execution of this handler I will remain blocked on the mutex\n"); + +} + +static void * start_routine(void *arg) +{ + int ret,i,signal,err=0; + int nthread = (int) arg; + struct sigaction sa; + struct timespec maxtime; + rtl_sigset_t mask; + + struct sched_param p; + p . sched_priority = 1; + pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); + + maxtime.tv_sec=0; + maxtime.tv_nsec=100*1000*1000; + + rtl_printf("thread %d starts on CPU%d\n", nthread, rtl_getcpuid()); + ret = pthread_mutex_trylock(&mutex); + rtl_printf ("thread %d: pthread_mutex_trylock returned %d\n", nthread, ret); + + /* This code will be executed by thread with nthread == o */ + if (nthread==0){ + rtl_printf("THREAD %d, sending signals to others thread blocked on the mutex count:%d\n",nthread,count); + nanosleep(hrt2ts(100*1000),NULL); + for (i=1;i sigaction(%d,&sa,NULL) FAILING, err:%d.\n",nthread,signal,err); + } + + rtl_sigfillset(&mask); + rtl_sigdelset(&mask,signal); + + pthread_sigmask(SIG_SETMASK,&mask,NULL); + + + if (ret != 0) { + rtl_printf("thread %d: about to pthread_mutex_timedlock\n", nthread); + ret = pthread_mutex_timedlock (&mutex,hrt2ts(gethrtime()+timespec_to_ns(&maxtime))); + rtl_printf("thread %d: pthread_mutex_timedlock returned %d\n", nthread, ret); + } + + if (ret==ETIMEDOUT){ + rtl_printf("TEST SUCCESFULY PASSED for thread %d\n",nthread); + } + } + + nanosleep(&maxtime,NULL); + ret = pthread_mutex_unlock (&mutex); + rtl_printf("thread %d: pthread_mutex_unlock returned %d\n", nthread, ret); + + return (void *) (35 + nthread); +} + + +int init_module(void) +{ + int ret; + int i; + pthread_attr_t attr; + + pthread_mutex_init (&mutex, 0); + + rtl_printf("RTLinux mutex test starts on CPU%d\n", rtl_getcpuid()); + pthread_attr_init (&attr); + for (i = 0; i < NTASKS; i++) { + /* try to run one thread on another CPU */ + if (i == 1 && rtl_cpu_exists(!rtl_getcpuid())) { + pthread_attr_setcpu_np(&attr, !rtl_getcpuid()); + } + + ret = pthread_create (&thread[i], &attr, start_routine, (void *) i); + if (ret) { + rtl_printf("failed to create a thread\n"); + return ret; + } + } + + + return 0; +} + +void cleanup_module(void) { + int i; + void *retval; + + for (i=0;i to continue" + @read junk + -rmmod sound + -rmmod rt_process + -rmmod frank_module + (cd ../../../; scripts/rmrtl) + @echo "Now insert the fifo and scheduler" + @echo "Type to continue" + @read junk + (cd ../../../; scripts/insrtl) + @echo "Now start the real-time tasks module" + @echo "Type to continue" + @read junk + @insmod sig_nanosleep.o + @sleep 6 + @echo "Now let's stop the application" + @echo "Type to finish" + @read junk + @rmmod sig_nanosleep + +include ../../../Rules.make diff -NaurbB rtlinux-3.2-pre1.old/examples/signals/nanosleep/sig_nanosleep.c rtlinux-3.2-pre1/examples/signals/nanosleep/sig_nanosleep.c --- rtlinux-3.2-pre1.old/examples/signals/nanosleep/sig_nanosleep.c 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/signals/nanosleep/sig_nanosleep.c 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,127 @@ +/* + * POSIX.1 Signals test program + * + * Written by J. Vidal + * Copyright (C) Dec, 2002 OCERA Consortium. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2. + * + * Testing nanosleep function when receiving signals. + * + */ + +#include +#include + +#define NTASKS 3 +#define ONEMILISEC (long long)1000*1000 +#define ITERS 2 + + +static pthread_t thread[NTASKS]; +long long start_time=0; + +static void signal_handler(int sig){ + rtl_printf("Signal handler called for signal:%d\n",sig); +} + +static void *start_routine(void *arg) +{ + struct sched_param p; + struct timespec sleep_period,remaining; + struct sigaction sa; + rtl_sigset_t mask; + int signal=0, err=0,i,j=0; + long long period=0; + int param=(unsigned) arg; + + //blocking all user signals. + rtl_sigfillset(&mask); + pthread_sigmask(SIG_SETMASK,&mask,NULL); + + p . sched_priority =param; + pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); + + sa.sa_handler=signal_handler; + sa.sa_mask=0; + sa.sa_flags=0; + + signal=RTL_SIGUSR2+param; + + if ((err=sigaction(signal,&sa,NULL))<0 ){ + rtl_printf("sigaction(SIGRTMIN,&sa,NULL) FAILING, err:%d.\n",err); + } + + sleep_period.tv_sec=1+param; + remaining.tv_sec=remaining.tv_nsec=sleep_period.tv_nsec=0; + + if (param!=0){ + + rtl_sigemptyset(&mask); + rtl_sigaddset(&mask,signal); + pthread_sigmask(SIG_UNBLOCK,&mask,NULL); + + while (j++ to continue" + @read junk + -rmmod sound + -rmmod rt_process + -rmmod frank_module + (cd ../../../; scripts/rmrtl) + @echo "Now insert the fifo and scheduler" + @echo "Type to continue" + @read junk + (cd ../../../; scripts/insrtl) + @echo "Now start the real-time tasks module" + @echo "Type to continue" + @read junk + @insmod pending.o + @echo "Running real-time application for two seconds!" + @sleep 2 + @echo "Now let's stop the application" + @echo "Type to finish" + @read junk + @rmmod pending + +include ../../../Rules.make diff -NaurbB rtlinux-3.2-pre1.old/examples/signals/pending/pending.c rtlinux-3.2-pre1/examples/signals/pending/pending.c --- rtlinux-3.2-pre1.old/examples/signals/pending/pending.c 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/signals/pending/pending.c 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,127 @@ +/* + * POSIX.1 Signals test program + * + * Written by J. Vidal + * Copyright (C) Dec, 2002 OCERA Consortium. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2. + * + * Simple program to test signal delivery order and global sigactions. + * + */ + +#include +#include + +#define NTASKS 2 +static pthread_t thread[NTASKS]; +static int sig_rec[NTASKS]; +#define MAXSIGNALS_REC 100 + +static void signal_handler(int signal){ + rtl_printf("Signal handler called for signal %d\n",signal); +} + + +static void *start_routine(void *arg) +{ + struct sched_param p; + struct sigaction sa; + int err,i,signal,count=0; + rtl_sigset_t set; + int param=(unsigned) arg; + + + p . sched_priority =1; + pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); + + + sa.sa_handler=signal_handler; + sa.sa_mask=0; + sa.sa_flags=0; + + rtl_printf("Program actions for no valid signals. Expect failure\n"); + + signal=RTL_SIGUSR1-1; + if ((err=sigaction(signal,&sa,NULL))<0 ){ + rtl_printf("sigaction(%d,&sa,NULL) FAILING, err:%d.\n",signal,err); + } + + signal=RTL_SIGRTMAX+1; + if ((err=sigaction(signal,&sa,NULL))<0 ){ + rtl_printf("sigaction(%d,&sa,NULL) FAILING, err:%d.\n",signal,err); + } + + rtl_sigfillset(&set); + pthread_sigmask(SIG_BLOCK,&set,NULL); + + if (!param){ + rtl_printf("Thread %d programing all user signals\n",param); + for (i=RTL_SIGUSR1; i<=RTL_SIGRTMAX; i++){ + rtl_sigdelset(&set,i); + if ((err=sigaction(i,&sa,NULL))<0 ){ + rtl_printf("sigaction(%d,&sa,NULL) FAILING, err:%d.\n",i,err); + } + } + while (count=RTL_SIGUSR1; i-=2){ + rtl_sigdelset(&set,i); + if ((err=sigaction(i,&sa,NULL))<0 ){ + rtl_printf("sigaction(%d,&sa,NULL) FAILING, err:%d.\n",i,err); + } + } + while (count=RTL_SIGUSR1; i--){ + pthread_kill(thread[(param+1)%NTASKS],i); + } + rtl_printf("Thread %d waiting for signals\n",param); + sigsuspend(&set); + count++; + } + } + + sig_rec[param]=count; + + rtl_sigfillset(&set); + //Block thread, so all user signals are blocked. + sigsuspend(&set); + + return 0; +} + +int init_module(void) { + int i; + + // Threads creation. + for (i=0;i (OCERA) \ No newline at end of file diff -NaurbB rtlinux-3.2-pre1.old/examples/signals/posixtest/sigaction/1-17.c rtlinux-3.2-pre1/examples/signals/posixtest/sigaction/1-17.c --- rtlinux-3.2-pre1.old/examples/signals/posixtest/sigaction/1-17.c 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/signals/posixtest/sigaction/1-17.c 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,79 @@ +/* + * Test case for assertion #1 of the sigaction system call that shows + * sigaction (when used with a non-null act pointer) changes the action + * for a signal. + * + * Steps: + * 1. Initialize a global variable to indicate the signal + * handler has not been called. (A signal handler of the + * prototype "void func(int signo);" will set the global + * variable to indicate otherwise. + * 2. Use sigaction to setup a signal handler for SIGUSR1 + * 3. Raise SIGUSR1. + * 4. Verify the global indicates the signal was called. +*/ + +#include +#include "compat.h" + +#define NTASKS 1 +static pthread_t thread[NTASKS]; + +int handler_called = 0; + +void handler(int signo) +{ + handler_called = 1; +} + +void * th_code (void * arg) +{ + struct sigaction act; + + act.sa_handler = handler; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + if (sigaction(SIGUSR1, &act, 0) == -1) { + perror("Unexpected error while attempting to setup test " + "pre-conditions"); + return -1; + } + + if (raise(SIGUSR1) == -1) { + perror("Unexpected error while attempting to setup test " + "pre-conditions"); + return -1; + } + + if (handler_called) { + printf("Test PASSED\n"); + return 0; + } + + printf("Test FAILED\n"); + return -1; +} + + +int init_module(void){ + int i; + + for(i=0;i +#include "compat.h" + +#define NTASKS 1 +static pthread_t thread[NTASKS]; + + +int handler_called = 0; + +void handler1(int signo) +{ +} + +void handler2(int signo) +{ +} + +void *th_code(void *arg) +{ + struct sigaction act; + struct sigaction oact; + + act.sa_handler = handler1; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + if (sigaction(SIGUSR1, &act, 0) == -1) { + perror("Unexpected error while attempting to setup test " + "pre-conditions"); + return -1; + } + + act.sa_handler = handler2; + sigemptyset(&act.sa_mask); + if (sigaction(SIGUSR1, &act, &oact) == -1) { + perror("Unexpected error while attempting to setup test " + "pre-conditions"); + return -1; + } + + if (oact.sa_handler == handler1) { + printf("Test PASSED\n"); + return 0; + } + + printf("Test Failed\n"); + return -1; +} + + +int init_module(void){ + int i; + + for(i=0;i +#include "compat.h" + +#define NTASKS 1 +static pthread_t thread[NTASKS]; +int handler_called = 0; + +void handler(int signo) +{ + handler_called = 1; +} + +void * th_code (void *arg) +{ + struct sigaction act; + struct sigaction oact; + + act.sa_handler = handler; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + if (sigaction(SIGUSR1, &act, 0) == -1) { + perror("Unexpected error while attempting to setup test " + "pre-conditions"); + return -1; + } + + if (sigaction(SIGUSR1, 0, &oact) == -1) { + perror("Unexpected error while attempting to setup test " + "pre-conditions"); + return -1; + } + + + if (raise(SIGUSR1) == -1) { + perror("Unexpected error while attempting to setup test " + "pre-conditions"); + return -1; + } + + if (handler_called) { + printf("Test PASSED\n"); + return 0; + } + + printf("Test FAILED\n"); + return -1; +} + + + +int init_module(void){ + int i; + + for(i=0;i +#include + +#define SIGUSR1 RTL_SIGUSR1 + + +#define printf rtl_printf +#define perror rtl_printf +#define sigemptyset rtl_sigemptyset + +extern int raise(int signal) { + int err=0; + + err=pthread_kill(pthread_self(),signal); + rtl_schedule(); + return err; +} + diff -NaurbB rtlinux-3.2-pre1.old/examples/signals/posixtest/sigaction/Makefile rtlinux-3.2-pre1/examples/signals/posixtest/sigaction/Makefile --- rtlinux-3.2-pre1.old/examples/signals/posixtest/sigaction/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/signals/posixtest/sigaction/Makefile 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,53 @@ +SOURCE:=$(shell (ls *.c)) +MODULES=$(shell for i in `ls *.c | awk -F. '{print $$1}' `; do echo $$i".o" ; done ) +MODNAMES=$(shell for i in `ls *.c | awk -F. '{print $$1}' `; do echo $$i; done ) +include ../../../../rtl.mk + +clean: + rm -f *.o +all: + $(MAKE) $(MODULES) +help: + @echo "/***************************************************************/" + @echo "/* Open POSIX test suite addapted to RTLinux. */" + @echo "/***************************************************************/" +test: all help + @echo "First we remove any existing rtl-modules" + @echo "You may see error warnings from \"make\" - ignore them" + @echo "Type to continue" + @read junk + -rmmod sound + -rmmod rt_process + -rmmod frank_module + -(for i in $(MODNAMES) ; do rmmod $$i ; done) + (cd ../../../../; scripts/rmrtl) + @echo "Now insert the fifo and scheduler" + @echo "Type to continue" + @read junk + (cd ../../../../; scripts/insrtl) + @echo "Now start the real-time test tasks modules" + @echo "Type to continue" + @read junk + @dmesg -c + (for i in $(MODNAMES) ; do \ + echo ">------------------------------------------<" ; \ + echo " TESTING "$$i".o MODULE " ; \ + echo ">------------------------------------------<" ; \ + cat $$i.c | awk '{ if ( $$1 == "*" ) print $0 }' ; \ + insmod $$i.o; \ + if [[ $$i == "5-3" ]]; then \ + echo "Sleeping for 30 seconds" ; \ + sleep 30 ; \ + else \ + echo "Sleeping for 5 seconds" ; \ + sleep 5 ; \ + fi; \ + echo ">------------------------------------------<" ; \ + echo " TEST RESULTS: " ; \ + echo ">------------------------------------------<" ; \ + dmesg -c ;\ + rmmod $$i ; \ + echo "Type to continue" ; \ + read junk ; \ + done) +include ../../../../Rules.make diff -NaurbB rtlinux-3.2-pre1.old/examples/signals/README rtlinux-3.2-pre1/examples/signals/README --- rtlinux-3.2-pre1.old/examples/signals/README 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/signals/README 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,122 @@ +/* + * POSIX.1 Signals + * + * Written by J. Vidal + * Copyright (C) Dec, 2002 OCERA Consortium. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2. + * + * Programs to test POSIX.1 signals implementation. + * + */ + +Test programs +In this directory , there is a nice collection of 20 test +programs, distributed in separated directories. To load any +test program, type make test in the correspondent directory. +In the following list, a brief description of each one, +is provided: + +hello.c: + This is a trivial program in which a periodic thread +sends a signal to itself every time a condition is acomplished. +The signal handler for that signal prints a message saying +``Hello world! Signal handler called for signal ...'' + +signals.c: + This is a test program in which there is a master thread +and a user defined number of slaves. The master thread is +the only thread that is periodic. It sends a signal to each slave +in each activation. Slaves are suspended and waked up by it's signal +handler. After reciving a number of signals, the slave thread blocks +that signal with pthread_sigmask. After this no more signals +are delivered. + +wait_4_sig.c: + In this program, we prove most of implemented functionalities: +pthread_sigmask, sigsuspend, pthread_kill, terminating threads from signal + handlers, blocked mask ... The logic of the program consists in a master +that is sending a window of signals to a slave. Slave blocks all +signals each time except the one that they want to receive for that moment. +Only the handler for the signal that is unblocked will be executed. The other +signals generated don't have effect so they are blocked. + +signals.c: + This is a test program in which there is a master thread and a user +defined number of slaves. The master thread is the only thread that is periodic. +It sends a signal to each slave in each activation. Slaves are suspended and +waked up by it's signal handler. After reciving a number of signals, +the slave thread blocks that signal with pthread_sigmask. After this no more +signals are delivered. + +ign_signals.c: + In this test a master sends signals to all its slaves. Only odd +threads should get delivered generated signals. So the others threads have +installed the default handler or SIG_IGN. + +test.c: + This is a simple program to test that the execution of a signal handler +can be interrumpted by other higher priority threads. In this test two periodic +threads are wasting time when they execute its signal handler. +Be careful with the amount of computing they do in its signal handlers. +They can hang up slow processors. A hight priority thread expulses signal +handler executions periodically every 1 milisecond. Also a higher priority +signal handler expulses a lower. A chronogram of what its happening is shown +in file testlog.txt. The first task is linux. The second and the third are periodic +tasks that are executing huge quantity of computing on their signal handlers. +Last task is a high frequency periodic task. +Finally, priority is increassing with the number of the task. +This is, the first task the less prioritary, the last the most. + +sig_intr.c: + This program shows what happens when a non periodic thread +it's executing a handler and is interrumped by other hight priority thread. + +ign_signals.c: + In this test a master sends signals to all its slaves. +Only odd threads should get delivered generated signals. So the +others threads have installed the default handler or RTL_SIG_IGN. + +sig_prio.c: + In this program a thread sends a signal to a higher priority +thread. At this moment the higher priority thread should take the CPU. +Then it suspends signal generator to prove that has taken the CPU. + +sig_nanosleep.c: + In this program a thread is sleeping for a while. While it is sleeping +other thread generates a signal for it. Then the thread is interrumped and +shows the sleep time remained. + +sched.c: + This program implements a very simple version of the round robin +scheduler using a periodic thread and user signals. Each scheduled thread has +three signal handlers: the first suspends that thread while the second wake ups it. +Finally the third finishes it. The periodic thread has a handler that implements the +scheduling algorithm. Each time it has to schedule sends a signal to itself. +Then the handler for that signal sends a signal to suspend the current thread and +other to wake up next thread. Finally, when the scheduler finishes sends a signal +to kill all the scheduled threads. + + sig_sem.c: + In this program, various threads are blocked on a semaphore. +While they are blocked other thread generates a signal to no odd +semaphore blocked threads. Then no odd threads are interrumped and +gets out the semaphore. The other threads remain blocked. +Note: There is also, a test version for timed semaphores on file sig_timedsem.c + +sig_mutex.c: + In this program, various threads are blocked on a mutex. +While they are blocked on the mutex, the master threads sends signals to them. +At this point blocked threads must execute the signal handler and remain blocked. +Note: There is also, a test version for timed mutexes on file sig_timedmutex.c. + +sig_condvar.c: + In this program a real-time thread before becoming blocked on a condition +variable sends a signal to itself. After becoming blocked it executes the signal +handler for previous generated signal. After this, it resumes blocked on the condition variable. + +pending.c: Simple program to test signal delivery order and global sigactions. + +posixtestsuite: In this directory you will find three test program testing sigaction functionality. \ No newline at end of file diff -NaurbB rtlinux-3.2-pre1.old/examples/signals/rr_sched/Makefile rtlinux-3.2-pre1/examples/signals/rr_sched/Makefile --- rtlinux-3.2-pre1.old/examples/signals/rr_sched/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/signals/rr_sched/Makefile 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,40 @@ +all: sched.o + +include ../../../rtl.mk +clean: + rm -f *.o + +help: + @echo "/****************************************************************/" + @echo "/****************************************************************/" + @echo "/* This program implements a very simple version of the round */" + @echo "/* robin scheduler using a periodic thread and user signals. */" + @echo "/****************************************************************/" + @echo "/****************************************************************/" + +test: all help + @echo "First we remove any existing rtl-modules" + @echo "You may see error warnings from \"make\" - ignore them" + @echo "Type to continue" + @read junk + -rmmod sound + -rmmod rt_process + -rmmod frank_module + (cd ../../../; scripts/rmrtl) + @echo "Now insert the fifo and scheduler" + @echo "Type to continue" + @read junk + (cd ../../../; scripts/insrtl) + @echo "Now start the real-time tasks module" + @echo "Type to continue" + @read junk + @insmod sched.o + @echo "Running real-time application for half a minit!" + @sleep 30 + @echo "Now let's stop the application" + @echo "Type to finish" + @read junk + @rmmod sched + +include ../../../Rules.make + diff -NaurbB rtlinux-3.2-pre1.old/examples/signals/rr_sched/sched.c rtlinux-3.2-pre1/examples/signals/rr_sched/sched.c --- rtlinux-3.2-pre1.old/examples/signals/rr_sched/sched.c 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/signals/rr_sched/sched.c 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,144 @@ +/* + * POSIX.1 Signals test program + * + * Written by J. Vidal + * Copyright (C) Dec, 2002 OCERA Consortium. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2. + * + * Test program implementing a trivial Round Robin scheduler with + * user signals. + * + */ + +#include +#include + +#define MAX_TASKS 7 +#define NTASKS 4 +#define SCHED_SIGNAL RTL_SIGUSR1 +#define WAKEUP_SIGNAL RTL_SIGUSR2 +#define SUSPEND_SIGNAL (WAKEUP_SIGNAL+MAX_TASKS) +#define DELETE_SIGNAL (SUSPEND_SIGNAL+MAX_TASKS) + + +pthread_t thread[MAX_TASKS]; +#define kill(th,sig) pthread_kill(thread[th],sig+th) + +static void sched_hdl(int sig){ + static int rr_current=0; + + rtl_printf("\n\n\nSignal handler called for signal :%d, ROUND ROBING SCHEDULING.\n",sig); + rtl_printf("Current :%d\n\n\n",rr_current % NTASKS); + if (++rr_current % NTASKS) kill(rr_current % NTASKS,WAKEUP_SIGNAL); + if (rr_current % NTASKS) kill(rr_current % NTASKS,SUSPEND_SIGNAL); +} + +static void wakeup_hdl(int sig){ + rtl_printf("Signal handler called for signal :%d, waking up thread\n",sig); + pthread_wakeup_np(pthread_self()); +} + +static void suspend_hdl(int sig){ + rtl_printf("Signal handler called for signal :%d, suspending thread\n",sig); + pthread_suspend_np(pthread_self()); +} + +static void delete_hdl(int sig){ + rtl_printf("Signal handler called for signal :%d, removing thread\n",sig); + pthread_exit(NULL); +} + +static void do_work(int who){ + static int i=0; + int j,k,m=0; + + rtl_printf("Hi, I am thread %d, just wasting time iter:%d\n",who,i++); + for (j=0;j<10;j++) + for (k=0;k<10;k++) + m+=i-j+k; + +} + +void * start_routine(void *arg) +{ int i=0,err=0,param; + struct sched_param p; + struct sigaction sa_wakeup,sa_suspend,sa_delete,sa_sched; + rtl_sigset_t mask; + + param=(unsigned) arg; + + if (param) + p . sched_priority = param; + else + p . sched_priority = MAX_TASKS; + + pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); + + if (param) { + + sa_wakeup.sa_handler=wakeup_hdl; + sa_suspend.sa_handler=suspend_hdl; + sa_delete.sa_handler=delete_hdl; + + if ((err=sigaction(WAKEUP_SIGNAL+param,&sa_wakeup,NULL))<0 ) + rtl_printf("sigaction(%d,&sa_wakeup,NULL) FAILING, errno:%d.\n",WAKEUP_SIGNAL,errno); + + if ((err=sigaction(SUSPEND_SIGNAL+param,&sa_suspend,NULL))<0 ) + rtl_printf("sigaction(%d,&sa_suspend,NULL) FAILING, errno:%d.\n",SUSPEND_SIGNAL,errno); + + if ((err=sigaction(DELETE_SIGNAL+param,&sa_delete,NULL))<0 ) + rtl_printf("sigaction(%d,&sa_delete,NULL) FAILING, errno:%d.\n",DELETE_SIGNAL,errno); + + rtl_sigfillset(&mask); + pthread_sigmask(SIG_SETMASK,&mask,NULL); + rtl_sigemptyset(&mask); + + rtl_sigaddset(&mask,WAKEUP_SIGNAL); + rtl_sigaddset(&mask,SUSPEND_SIGNAL); + rtl_sigaddset(&mask,DELETE_SIGNAL); + + while(1){ + sigsuspend(&mask); + do_work(param); + } + + } else { + sa_sched.sa_handler=sched_hdl; + if ((err=sigaction(SCHED_SIGNAL,&sa_sched,NULL))<0 ) + rtl_printf("sigaction(%d,&sa,NULL) FAILING, errno:%d.\n",SCHED_SIGNAL,errno); + + pthread_make_periodic_np (pthread_self(), gethrtime(), (long long)500*1000*1000); + } + + rtl_sigfillset(&mask); + rtl_sigdelset(&mask,SCHED_SIGNAL); + pthread_sigmask(SIG_SETMASK,&mask,NULL); + + while (i++<=100) { + pthread_wait_np (); + pthread_kill(pthread_self(),SCHED_SIGNAL); + i++; + } + + //Remove all scheduled threads. + for (i=0;i to continue" + @read junk + -rmmod sound + -rmmod rt_process + -rmmod frank_module + (cd ../../../; scripts/rmrtl) + @echo "Now insert the fifo and scheduler" + @echo "Type to continue" + @read junk + (cd ../../../; scripts/insrtl) + @echo "Now start the real-time tasks module" + @echo "Type to continue" + @read junk + @insmod sig_sem.o + @sleep 3 + @echo "Now let's stop the application" + @echo "Type to finish" + @read junk + @rmmod sig_sem + +include ../../../Rules.make diff -NaurbB rtlinux-3.2-pre1.old/examples/signals/semaphores/sig_sem.c rtlinux-3.2-pre1/examples/signals/semaphores/sig_sem.c --- rtlinux-3.2-pre1.old/examples/signals/semaphores/sig_sem.c 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/signals/semaphores/sig_sem.c 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,133 @@ +/* + * Added user signals to semaphores test, + * Dec, 2002 Josep Vidal (OCERA) + */ + +#include +#include +#include + +#define NTASKS 20 +#define ONEMILISEC (long long)1000*1000 +#define ITERS 5 + +static pthread_t thread[NTASKS]; +long long start_time=0; +static sem_t sem; +static int th_wakeup[NTASKS]; + +void sig_handler(int sig_rec){ + unsigned int thread_no; + + thread_no=(unsigned int)(sig_rec-RTL_SIGRTMIN); + rtl_printf("I'm thread %d, really blocked on a sem...\n",thread_no); + rtl_printf("but signals handlers are executed regardless being blocked in a sem\n"); + rtl_printf("After finishing handler execution for signal:%d, I will exit from the semaphore\n",sig_rec); +} + +static void *start_routine(void *arg) +{ + struct sched_param p; + struct sigaction sa; + int signal=0,err=0,j,iter=0; + long long period=0; + int param=(unsigned) arg; + rtl_sigset_t mask; + + p . sched_priority =1;//param; + pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); + + + // Block all signals except the ones you want to receive. + + if (param){ + rtl_sigfillset(&mask); + signal=RTL_SIGRTMIN+param; + + rtl_sigdelset(&mask,signal); + pthread_sigmask(SIG_SETMASK,&mask,NULL); + + rtl_printf("I am thread %d, programing handler for signal:%d\n",param,signal); + + sa.sa_handler=sig_handler; + sa.sa_mask=0; + sa.sa_flags=0; + + + if ((err=sigaction(signal,&sa,NULL))<0 ){ + rtl_printf("sigaction(%d,&sa,NULL) FAILING, err:%d.\n",signal,err); + } + } + + if (!param){ + sem_wait(&sem); + period=500*ONEMILISEC; + pthread_make_periodic_np (pthread_self(), start_time ,period ); + while (iter++ I want to signal not odd threads\n",param); + pthread_wait_np(); + + for (j=1;jmagic!=RTL_THREAD_MAGIC) + rtl_printf("TEST PANIC!!!!!! thread %d not a valid thread\n",j); + + // Send signals only to not odd numbers. + if (!(j%2)) pthread_kill(thread[j],RTL_SIGRTMIN+j); + } + } + } else { + rtl_sigfillset(&mask); + rtl_sigdelset(&mask,signal); + + // while(iter++ (OCERA) + */ + +#include +#include +#include + +#define NTASKS 3 +#define ONEMILISEC (long long)1000*1000 + +static pthread_t thread[NTASKS]; +long long start_time=0; +static sem_t sem; + +static void sig_handler(int sig_rec){ + unsigned int thread_no; + + thread_no=(unsigned int)(sig_rec-RTL_SIGRTMIN); + rtl_printf("I'm thread %d, temporally blocked (sem_timedwait) on a semaphore...\n",thread_no); + rtl_printf("but signals handlers are executed regardless being blocked in a sem\n"); + rtl_printf("After finishing handler execution for signal:%d, I will exit from the semaphore\n",sig_rec); + +} + +static void *start_routine(void *arg) +{ + struct sched_param p; + struct sigaction sa; + int signal=0,err=0,j; + int param=(unsigned) arg; + rtl_sigset_t mask; + + p . sched_priority =1;//param; + pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); + + sa.sa_handler=sig_handler; + sa.sa_mask=0; + sa.sa_flags=0; + + // Block all signals except the ones you want to receive. + if (param){ + rtl_sigfillset(&mask); + signal=RTL_SIGRTMIN+param; + + rtl_sigdelset(&mask,signal); + pthread_sigmask(SIG_SETMASK,&mask,NULL); + + rtl_printf("I am thread %d, programing handler for signal:%d\n",param,signal); + if ((err=sigaction(signal,&sa,NULL))<0 ){ + rtl_printf("sigaction(%d,&sa,NULL) FAILING, err:%d.\n",signal,err); + } + } + + if (!param){ + sem_wait(&sem); + usleep(1000); + rtl_printf("\n\n\n\n -- WAITING FOR THE OTHER TASKS -- \n\n\n"); + rtl_printf("THREAD %d--> I want to signal not odd threads\n",param); + + for (j=1;jmagic!=RTL_THREAD_MAGIC) + rtl_printf("TEST PANIC!!!!!! thread %d not a valid thread\n",j); + + // Send signals only to not odd numbers. + if (!(j%2)) pthread_kill(thread[j],RTL_SIGRTMIN+j); + } + + } else { + + rtl_sigfillset(&mask); + rtl_sigdelset(&mask,signal); + pthread_sigmask(SIG_SETMASK,&mask,NULL); + + rtl_printf("THREAD %d. Just before adquiring the sem and getting blocked.\n",param); + /* Ten seconds */ + err = sem_timedwait (&sem, hrt2ts(clock_gethrtime(CLOCK_REALTIME) + 1000*1000*1000LL * 2)); + rtl_printf("THREAD %d. Something has take me from my timed wait ->errno:%d.\n",param,errno); + if (!(param % 2)){ + if (errno == EINTR){ + rtl_printf("\n\n TEST SUCCESFULLY PASSED!!!! A signal has take thread %d out from the semaphore errno %d \n\n",param,errno); + } else { + rtl_printf("\n\n TEST NOT PASSED for thread %d\n\n",param); + } + } + } + + pthread_make_periodic_np(pthread_self(), gethrtime(),1000*1000*1000); + while(1) pthread_wait_np(); + + return 0; +} + +int init_module(void) { + int i; + + sem_init(&sem,0,1); + + start_time=gethrtime()+1000*ONEMILISEC; + + // Threads creation. + for (i=0;i to continue" + @read junk + -rmmod sound + -rmmod rt_process + -rmmod frank_module + (cd ../../../; scripts/rmrtl) + @echo "Now insert the fifo and scheduler" + @echo "Type to continue" + @read junk + (cd ../../../; scripts/insrtl) + @echo "Now start the real-time tasks module" + @echo "Type to continue" + @read junk + @insmod sig_intr.o + @sleep 3 + @echo "Now let's stop the application" + @echo "Type to finish" + @read junk + @rmmod sig_intr + +include ../../../Rules.make diff -NaurbB rtlinux-3.2-pre1.old/examples/signals/sig_intr/sig_intr.c rtlinux-3.2-pre1/examples/signals/sig_intr/sig_intr.c --- rtlinux-3.2-pre1.old/examples/signals/sig_intr/sig_intr.c 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/signals/sig_intr/sig_intr.c 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,112 @@ +/* + * POSIX.1 Signals test program + * + * Written by J. Vidal + * Copyright (C) Dec, 2002 OCERA Consortium. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2. + * + * Testing signal handlers preemption. + * + */ + +#include +#include + +#define SIGUSR1 RTL_SIGUSR1 +#define NTASKS 2 +static pthread_t thread[NTASKS]; +#define ITERS 100 +static int count=0; + +static void signal_handler(int signal){ + int i,j,k,m=0; + + rtl_printf("Signal handler called for signal %d, just wasting time\n",signal); + for (i=0;i<10;i++){ + rtl_printf(" Signal handler computing m:%d\n",m); + for (j=0;j to continue" + @read junk + -rmmod sound + -rmmod rt_process + -rmmod frank_module + (cd ../../../; scripts/rmrtl) + @echo "Now insert the fifo and scheduler" + @echo "Type to continue" + @read junk + (cd ../../../; scripts/insrtl) + @echo "Now start the real-time tasks module" + @echo "Type to continue" + @read junk + @insmod signals.o + @sleep 5 + @echo "Now let's stop the application" + @echo "Type to finish" + @read junk + @rmmod signals + +include ../../../Rules.make diff -NaurbB rtlinux-3.2-pre1.old/examples/signals/signals/signals.c rtlinux-3.2-pre1/examples/signals/signals/signals.c --- rtlinux-3.2-pre1.old/examples/signals/signals/signals.c 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/signals/signals/signals.c 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,133 @@ +/* + * POSIX.1 Signals test program + * + * Written by J. Vidal + * Copyright (C) Dec, 2002 OCERA Consortium. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2. + * + * Testing pending and blocked masks of user signals. + * + */ +#include +#include + +#define SIGRTMIN RTL_SIGRTMIN +#define NTASKS 4 +#define ONEMILISEC (long long)1000*1000 +static pthread_t thread[NTASKS]; +long long start_time=0; + +static void waste_time(int i){ + int j,k,l,m=0; + + // Consume time + for (j=0;j<(10+10*i);j++) + for (k=0;k<10;k++) + for (l=0;l<10;l++) + m=m+j-k+l; +} + +static void send_signals(void){ + int i=0; + int target_thread_no=0; + + rtl_printf("I am the master & I'm just sending signals to the rest of threads.\n"); + // Wake up the rest of threads + for (i=1 ;imagic == RTL_THREAD_MAGIC) + pthread_kill(thread[target_thread_no],SIGRTMIN+i); + else + rtl_printf("thread:%d not a valid thread.\n",target_thread_no); + } +} + + +static void signal_handler(int sig){ + rtl_printf("I am a slave thread executing the handeler for signal:%d \n",sig); + rtl_printf("Waking up!\n"); + pthread_wakeup_np(pthread_self()); +} + + +static void *start_routine(void *arg) +{ + struct sched_param p; + struct sigaction sa; + int signal; + int err; + long period; + static int count=0; + rtl_sigset_t set,oset; + int param=(unsigned) arg; + + p . sched_priority =param; + pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); + + period=(long)500*ONEMILISEC; + signal=SIGRTMIN+param; + + if (param){ + sa.sa_handler=signal_handler; + sa.sa_mask=0; + sa.sa_flags=0; + + if ((err=sigaction(signal,&sa,NULL))<0 ){ + rtl_printf("sigaction(signal,&sa,NULL) FAILING, err:%d.\n",signal,err); + } + } + + // only one task is periodic. The others are woken up by signals + if (param == 0) { + rtl_printf("Only one task is periodic. The others are waken up by signals\n"); + pthread_make_periodic_np (pthread_self(), start_time ,period ); + + while (1) { + send_signals(); + pthread_wait_np(); + } + } else { + while (1){ + pthread_suspend_np(pthread_self()); + rtl_printf("Slave thread nr:%d. Just wasting time\n",param); + waste_time(signal); + if (count++> signal){ + rtl_printf("Slave thread tired of reciving signal %d, %d times.\n",signal,signal); + rtl_printf("Just blocking it. After this, It will remain suspended forever and ever!\n"); + rtl_sigemptyset(&set); + rtl_sigaddset(&set,signal); + pthread_sigmask(SIG_BLOCK, &set,&oset ); + } + } + } + + return 0; +} + +int init_module(void) { + int i; + + start_time=1000*ONEMILISEC; + + // Threads creation. + for (i=0;i to continue" + @read junk + -rmmod sound + -rmmod rt_process + -rmmod frank_module + (cd ../../../; scripts/rmrtl) + @echo "Now insert the fifo and scheduler" + @echo "Type to continue" + @read junk + (cd ../../../; scripts/insrtl) + @echo "Now start the real-time tasks module" + @echo "Type to continue" + @read junk + @insmod sig_prio.o + @sleep 3 + @echo "Now let's stop the application" + @echo "Type to finish" + @read junk + @rmmod sig_prio + +include ../../../Rules.make diff -NaurbB rtlinux-3.2-pre1.old/examples/signals/sig_prio/sig_prio.c rtlinux-3.2-pre1/examples/signals/sig_prio/sig_prio.c --- rtlinux-3.2-pre1.old/examples/signals/sig_prio/sig_prio.c 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/signals/sig_prio/sig_prio.c 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,91 @@ +/* + * POSIX.1 Signals test program + * + * Written by J. Vidal + * Copyright (C) Dec, 2002 OCERA Consortium. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2. + * + * Testing pthread_kill real time constraints. + * + */ +#include +#include + +#define SIGUSR1 RTL_SIGUSR1 +#define NTASKS 2 +static pthread_t thread[NTASKS]; + +static void signal_handler(int signal){ + int i; + + rtl_printf("Signal handler called for signal %d\n",signal); + rtl_printf("TEST SUCCED!!!!! A lower priority thread has send me a signal\n"); + rtl_printf("and I have take the CPU\n"); + rtl_printf("Now suspending all threads\n"); + + for (i=0;i to continue" + @read junk + -rmmod sound + -rmmod rt_process + -rmmod frank_module + (cd ../../../; scripts/rmrtl) + @echo "Now insert the fifo and scheduler" + @echo "Type to continue" + @read junk + (cd ../../../; scripts/insrtl) + @echo "Now start the real-time tasks module" + @echo "Type to continue" + @read junk + @insmod test.o + @sleep 10 + @echo "Now let's stop the application" + @echo "Type to finish" + @read junk + @rmmod test + +include ../../../Rules.make diff -NaurbB rtlinux-3.2-pre1.old/examples/signals/test/test.c rtlinux-3.2-pre1/examples/signals/test/test.c --- rtlinux-3.2-pre1.old/examples/signals/test/test.c 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/signals/test/test.c 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,111 @@ +/* + * POSIX.1 Signals test program + * + * Written by J. Vidal + * Copyright (C) Dec, 2002 OCERA Consortium. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2. + * + * Test that the execution of a signal handler + * can be interrumpted by other higher priority threads + * + */ + +#include +#include + +#define SIGUSR1 RTL_SIGUSR1 +#define NTASKS 3 +#define ITERS 1000*1000 +static pthread_t thread[NTASKS]; + + +static int waste_time(int param){ + int j,k,l,m=0; + + // Consume time + for (j=0;j<=param;j++) + for (k=0;k<10;k++) + for (l=0;l<100;l++) + m=m+j-k+l; + + return j; +} + +static void signal_handler(int signal){ + int ret=0; + + rtl_printf("Signal handler called for signal %d\n",signal); + rtl_printf("This signal handler just wastes time\n"); + ret=waste_time(signal*100); + + if (ret>=(signal*100)) rtl_printf("Signal handler for signal %d about to end \n",signal); + +} + +static void *hight_prio_routine(void *arg){ + int i=0; + struct sched_param p; + p.sched_priority=100; + pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); + + pthread_make_periodic_np (pthread_self(), gethrtime(),1*1000*1000); + while(i++ to continue" + @read junk + -rmmod sound + -rmmod rt_process + -rmmod frank_module + (cd ../../../; scripts/rmrtl) + @echo "Now insert the fifo and scheduler" + @echo "Type to continue" + @read junk + (cd ../../../; scripts/insrtl) + @echo "Now start the real-time tasks module" + @echo "Type to continue" + @read junk + @insmod wait_4_sig.o + @sleep 6 + @echo "Now let's stop the application" + @echo "Type to finish" + @read junk + @rmmod wait_4_sig + +include ../../../Rules.make diff -NaurbB rtlinux-3.2-pre1.old/examples/signals/wait_4_sig/wait_4_sig.c rtlinux-3.2-pre1/examples/signals/wait_4_sig/wait_4_sig.c --- rtlinux-3.2-pre1.old/examples/signals/wait_4_sig/wait_4_sig.c 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/examples/signals/wait_4_sig/wait_4_sig.c 2003-07-17 10:52:44.000000000 +0200 @@ -0,0 +1,109 @@ +/* + * POSIX.1 Signals test program + * + * Written by J. Vidal + * Copyright (C) Dec, 2002 OCERA Consortium. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2. + * + * Test most of implemented functionalities: + * pthread_sigmask, sigsuspend, pthread_kill, terminating threads from signal + * handlers, blocked mask ... + */ + +#include +#include + +#define NTASKS 2 +static pthread_t thread[NTASKS]; +#define ACK RTL_SIGUSR1 +int last_sig_rec=0; + +static void signal_handler(int signal){ + rtl_printf("Signal handler called for signal %d\n",signal); +} + +static void ack_hdl(int signal){ + static int i=0; + rtl_printf("Acknolegment %d received\n",i++); +} + +static void *start_routine(void *arg) +{ + struct sched_param p; + struct sigaction sa; + int err,i=0,j=0; + rtl_sigset_t set; + int param=(unsigned) arg; + + p . sched_priority =param; + pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); + + rtl_sigfillset(&set); + pthread_sigmask(SIG_BLOCK,&set,NULL); + + if (!param){ + sa.sa_handler=ack_hdl; + if ((err=sigaction(ACK,&sa,NULL))<0 ){ + rtl_printf("sigaction(%d,&sa,NULL) FAILING, err:%d.\n",i,err); + } + rtl_sigdelset(&set,ACK); + j=RTL_SIGUSR1+1; + + while (1) { + rtl_printf("Master thread %d waiting acknoledgment before continuing \n",param); + sigsuspend(&set); + rtl_printf("Master thread %d sending a window of all signals. Only one is received each time \n",param); + for (i=RTL_SIGUSR1; i<=j; i++){ + pthread_kill(thread[(param+1)%NTASKS],i); + } + j++; + } + } else { + sa.sa_handler=signal_handler; + rtl_printf("Slave thread %d programing all user signals except RTL_SIGUSR1(overwritting previous programmed)\n",param); + for (i=RTL_SIGUSR1+1;i<=RTL_SIGRTMAX ;i++){ + + if ((err=sigaction(i,&sa,NULL))<0 ){ + rtl_printf("sigaction(%d,&sa,NULL) FAILING, err:%d.\n",i,err); + } + + rtl_printf("Slave thread %d waiting for signal %d \n",param,i); + pthread_kill(thread[(param+1)%NTASKS],ACK); + rtl_sigdelset(&set,i); + sigsuspend(&set); + rtl_sigfillset(&set); + last_sig_rec=i; + + } + } + + return 0; +} + +int init_module(void) { + int i; + + // Threads creation. + for (i=0;i + /* * RTLinux signal and the user-level RTLinux signals conflict. * This is ok since users should NOT be making RTLinux calls @@ -38,6 +40,10 @@ #include #endif +//#ifdef _RTL_POSIX_SIGNALS +#include +//#endif + struct rtl_sigaction { union { void (*_sa_handler)(int); @@ -45,6 +51,9 @@ } _u; int sa_flags; unsigned long sa_focus; +#ifdef _RTL_POSIX_SIGNALS + struct rtl_thread_struct *owner; +#endif rtl_sigset_t sa_mask; }; @@ -56,6 +65,13 @@ #define RTL_SIGLOCALIRQMIN 512 #define RTL_SIGIRQMAX 1024 +#ifdef _RTL_POSIX_SIGNALS +// Thread signals comes from 7 to 31. +#define RTL_THREAD_SIGNALS_MASK 0xFFFFFF80 +/* Array of sigactions. Thread signals from (7..31) */ +extern struct sigaction rtl_sigact[RTL_SIGIRQMAX]; +#endif + extern int sigaction(int sig, const struct sigaction *act, struct sigaction *oact); extern int sigprocmask(int how, const rtl_sigset_t *set, rtl_sigset_t *oset); extern int pthread_sigmask(int how, const rtl_sigset_t *set, rtl_sigset_t *oset); diff -NaurbB rtlinux-3.2-pre1.old/include/rtl_malloc.h rtlinux-3.2-pre1/include/rtl_malloc.h --- rtlinux-3.2-pre1.old/include/rtl_malloc.h 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/include/rtl_malloc.h 2003-07-17 11:02:54.000000000 +0200 @@ -0,0 +1,155 @@ +/* + * Doubly indexed dynamic memory allocator (DIDMA) + * Version 1.0 + * + * Written by Miguel Masmano Tello + * Copyright (C) Dec, 2002 OCERA Consortium + * Release under the terms of the GNU General Public License Version 2 + * + */ + +#ifndef _DOUBLY_INDEXED_MALLOC_H_ +#define _DOUBLY_INDEXED_MALLOC_H_ + + +/*------------------------------------------------------------------------*/ +/******************************/ +/* CONFIGURATION PARAMETERS */ +/******************************/ + +// The following parameters allows to tune DIDMA + +/* DIDMA_PREF defines the prefix + used by all DIDMA functions */ +// #define WITH_RTL_PREFIX + +/* + * MAX_FL_INDEX defines the maximum first index which + * will be used by DIDMA. The maximum first index is + * calculated in the init_memory_pool (size) + * + * if (log2 (size) <= MAX_FL_INDEX) then + * max_fl_index := log2 (size); + * else + * max_fl_index := MAX_FL_INDEX; + * end if; + * + */ + +#define MAX_FL_INDEX 24 // DIDMA default MAX_FL_INDEX is 16 MBytes + +/*------------------------------------------------------------------------*/ + +#if defined(__KERNEL__) && !defined(__RTL__) +#error "This modules can only be used in RTLinux or user space" +#endif + +#include + +#ifdef __RTL__ + +/* RTLinux module */ + +#include + +#define PRINT_MSG rtl_printf +#define PRINT_DBG_C(message) rtl_printf(message) +#define PRINT_DBG_D(message) rtl_printf("%i", message); +//#define PRINT_DBG_F(message) rtl_printf("%f", message); +#define PRINT_DBG_H(message) rtl_printf("%x", message); + +#else + +/* User space */ + +#include +#define PRINT_MSG printf +#define PRINT_DBG_C(message) printf(message) +#define PRINT_DBG_D(message) printf("%i", message); +#define PRINT_DBG_F(message) printf("%f", message); +#define PRINT_DBG_H(message) printf("%x", message); + +#endif + +extern char *main_buffer; // This buffer is associated with + // a block of memory by the user + +/* + * associate buffer allows to indicate to DIDMA that one specific + * buffer must be used by default, this allow to the user to use + * malloc, free, calloc and realloc functions + */ + +#define associate_buffer(ptr) main_buffer = (char *) ptr; + +/* + * max_sl_log2_index defines the maximum second index which will be + * used by DIDMA. + * + * max_sl_log2_index allows to the user to tune the maximum internal + * fragmentation, but a high max_sl_log2_index value will cause big + * DIDMA structure. + * + * max_sl_log2_index max. internal fragmentation (approximately) + * ----------------- ------------------------------------------- + * 1 25 % + * 2 12.5 % + * 3 6.25 % + * 4 3.125 % + * 5 1.563 % + */ + +// max_size is in Kbytes +int init_memory_pool (int max_size, + int max_sl_log2_index, char *block_ptr); + +void destroy_memory_pool (char *block_ptr); + +/* see man malloc */ +#ifdef WITH_RTL_PREFIX +#define rtl_malloc(size) rtl_malloc_ex (size, main_buffer); +void *rtl_malloc_ex (size_t size, char *block_ptr); +#else +#define malloc(size) malloc_ex (size, main_buffer); +void *malloc_ex (size_t size, char *block_ptr); +#endif + +/* see man realloc */ +#ifdef WITH_RTL_PREFIX +#define rtl_realloc(p, new_len) rtl_realloc_ex (p, new_len, main_buffer); +void *rtl_realloc_ex (void *p, size_t new_len, char *block_ptr); +#else +#define realloc(p, new_len) realloc_ex (p, new_len, main_buffer); +void *realloc_ex (void *p, size_t new_len, char *block_ptr); +#endif + +/* see man calloc */ +#ifdef WITH_RTL_PREFIX +#define rtl_calloc(nelem, elem_size) \ +rtl_calloc_ex (nelem, elem_size, main_buffer); +void *rtl_calloc_ex (size_t nelem, size_t elem_size, char *block_ptr); +#else +#define calloc(nelem, elem_size) \ +calloc_ex (nelem, elem_size, main_buffer); +void *calloc_ex (size_t nelem, size_t elem_size, char *block_ptr); +#endif + +/* + * see man free + * + * free () is only guaranteed to work if ptr is the address + * of a block allocated by rt_malloc() (and not yet freed). + */ + +#ifdef WITH_RTL_PREFIX +#define rtl_free(ptr) rtl_free_ex (ptr, main_buffer); +void rtl_free_ex (void *ptr, char *block_ptr); +#else +#define free(ptr) free_ex (ptr, main_buffer); +void free_ex (void *ptr, char *block_ptr); +#endif + +void free_blocks_status (char *block_ptr); +void structure_status (char *block_ptr); + +#endif // #ifndef _DOUBLY_INDEXED_MALLOC_H_ diff -NaurbB rtlinux-3.2-pre1.old/include/rtl_sched.h rtlinux-3.2-pre1/include/rtl_sched.h --- rtlinux-3.2-pre1.old/include/rtl_sched.h 2002-11-05 17:55:52.000000000 +0100 +++ rtlinux-3.2-pre1/include/rtl_sched.h 2003-07-17 10:52:44.000000000 +0200 @@ -96,7 +96,11 @@ #define RTL_PRIO(th) ((th)->sched_param.sched_priority) -enum {RTL_CANCELPENDING, RTL_CANCELTYPE, RTL_THREAD_JOINABLE, RTL_THREAD_FINISHED, RTL_THREAD_TIMERARMED, RTL_THREAD_WAIT_FOR_JOIN, RTL_THREAD_OK_TO_FINISH_JOIN}; +enum {RTL_CANCELPENDING, RTL_CANCELTYPE, RTL_THREAD_JOINABLE, RTL_THREAD_FINISHED, RTL_THREAD_TIMERARMED, RTL_THREAD_WAIT_FOR_JOIN, RTL_THREAD_OK_TO_FINISH_JOIN +#ifdef _RTL_POSIX_SIGNALS + , RTL_THREAD_SIGNAL_INTERRUMPIBLE +#endif +}; #define RTL_MAX_SIGNAL 31 /* this is max for internal RTLinux signals */ /* these are bit positions */ @@ -107,6 +111,26 @@ #define RTL_SIGNAL_TIMER 5 #define RTL_SIGNAL_READY 6 +#ifdef _RTL_POSIX_SIGNALS +#define RTL_SIGNAL_HANDLER_EXECUTION_INPROGRESS 4 +#define RTL_SIGUSR1 (RTL_SIGNAL_READY+1) +#define RTL_SIGUSR2 (RTL_SIGUSR1+1) + +/* + * Trap and fault signals + * Added by Miguel Masmano + */ +#define RTL_SIGFPE (RTL_SIGUSR2+1) +#define RTL_SIGTRAP (RTL_SIGUSR2+2) +#define RTL_SIGSEGV (RTL_SIGUSR2+3) +#define RTL_SIGILL (RTL_SIGUSR2+4) +#define RTL_SIGBUS (RTL_SIGUSR2+5) +#define RTL_SIGHUP (RTL_SIGUSR2+6) + +#define RTL_SIGRTMIN (RTL_SIGUSR2+7) +#define RTL_SIGRTMAX RTL_MAX_SIGNAL +#endif + /*TODO How will this work on PPC */ #define RTL_LINUX_MIN_SIGNAL 256 /* signals to Linux start here. global then local */ #define RTL_LINUX_MAX_SIGNAL 1024 @@ -355,6 +379,10 @@ int pthread_kill(pthread_t , int signo); +#ifdef _RTL_POSIX_SIGNALS +#define HIGHER_PRIORITY_THREAD(th1,th2) (RTL_PRIO(th1)>RTL_PRIO(th2)) +#endif + extern inline int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) { attr->detachstate = detachstate; diff -NaurbB rtlinux-3.2-pre1.old/include/rtl_signal.h rtlinux-3.2-pre1/include/rtl_signal.h --- rtlinux-3.2-pre1.old/include/rtl_signal.h 2002-10-30 16:56:53.000000000 +0100 +++ rtlinux-3.2-pre1/include/rtl_signal.h 2003-07-17 10:52:44.000000000 +0200 @@ -9,6 +9,25 @@ #define RTL_SIGNAL_TIMER 5 #define RTL_SIGNAL_READY 6 + + +#define RTL_SIGUSR1 (RTL_SIGNAL_READY+1) +#define RTL_SIGUSR2 (RTL_SIGUSR1+1) + +/* + * Trap and fault signals + * Added by Miguel Masmano + */ +#define RTL_SIGFPE (RTL_SIGUSR2+1) +#define RTL_SIGTRAP (RTL_SIGUSR2+2) +#define RTL_SIGSEGV (RTL_SIGUSR2+3) +#define RTL_SIGILL (RTL_SIGUSR2+4) +#define RTL_SIGBUS (RTL_SIGUSR2+5) +#define RTL_SIGHUP (RTL_SIGUSR2+6) + +#define RTL_SIGRTMIN (RTL_SIGUSR2+7) +#define RTL_SIGRTMAX RTL_MAX_SIGNAL + /*TODO How will this work on PPC */ #define RTL_LINUX_MIN_SIGNAL 256 /* signals to Linux start here. global then local */ #define RTL_LINUX_MAX_SIGNAL 1024 diff -NaurbB rtlinux-3.2-pre1.old/Makefile rtlinux-3.2-pre1/Makefile --- rtlinux-3.2-pre1.old/Makefile 2002-11-05 17:43:17.000000000 +0100 +++ rtlinux-3.2-pre1/Makefile 2003-07-17 11:05:35.000000000 +0200 @@ -145,6 +145,10 @@ MODULE_DIRS += debugger endif +ifeq ($(CONFIG_OC_RTL_MALLOC),y) +MODULE_DIRS += rtl_malloc +endif + ifdef CONFIG_RTL_V1_API ifndef CONFIG_SMP MODULE_DIRS += semaphores @@ -241,9 +245,10 @@ endif symlinks: dummy - rm -f include/arch main/arch + rm -f include/arch main/arch rtl_malloc/arch ln -s $(ARCH) include/arch ln -s $(ARCH) main/arch + ln -s $(ARCH) rtl_malloc/arch checklinux: @echo Using RT-Linux kernel source tree in $(RTLINUX) diff -NaurbB rtlinux-3.2-pre1.old/rtl_malloc/.depend rtlinux-3.2-pre1/rtl_malloc/.depend --- rtlinux-3.2-pre1.old/rtl_malloc/.depend 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/rtl_malloc/.depend 2003-07-17 11:02:02.000000000 +0200 @@ -0,0 +1,5 @@ +rtl_malloc.o: \ + /usr/src/rtlinux/rtlinux-3.2-pre2/include/rtl_malloc.h \ + arch/bits.h \ + $(wildcard /usr/src/rtlinux/rtlinux-3.2-pre2/include/config/bigphysarea.h) \ + $(wildcard /usr/src/rtlinux/rtlinux-3.2-pre2/include/config/bigphys/area.h) diff -NaurbB rtlinux-3.2-pre1.old/rtl_malloc/i386/bits.h rtlinux-3.2-pre1/rtl_malloc/i386/bits.h --- rtlinux-3.2-pre1.old/rtl_malloc/i386/bits.h 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/rtl_malloc/i386/bits.h 2003-07-17 11:02:02.000000000 +0200 @@ -0,0 +1,92 @@ +/* + * Some of this code has been taken from bitops.h + * Copyright 1992, Linus Torvalds. + * + * Others functions has been added by + * Miguel Masmano Tello + * Copyright (C) Feb, 2003 OCERA Consortium + * Release under the terms of the GNU General Public License Version 2 + */ + +#define ADDR (*(volatile long *) addr) + +/** + * ffs - find first bit set + * @x: the word to search + * + * This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + */ + + +static __inline__ int DIDMA_ffs(int x) +{ + int r; + + __asm__("bsfl %1,%0\n\t" + "jnz 1f\n\t" + "movl $-1,%0\n" + "1:" : "=r" (r) : "g" (x)); + return r; +} + + +/** + * fls - find last bit set + * @x: the word to search + * + * This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + */ +static __inline__ int DIDMA_fls(int x) +{ + int r; + + __asm__("bsrl %1,%0\n\t" + "jnz 1f\n\t" + "movl $-1,%0\n" + "1:" : "=r" (r) : "g" (x)); + return r; +} + +/** + * __set_bit - Set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * Unlike set_bit(), this function is non-atomic and may be reordered. + * If it's called on the same region of memory simultaneously, the effect + * may be that only one operation succeeds. + */ +/* +static __inline__ void __set_bit(int nr, volatile void * addr) +{ + __asm__( + "btsl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +} +*/ +/** + * __clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is non-atomic and may be reordered. However, it does + * not contain a memory barrier, so if it is used for locking purposes, + * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() + * in order to ensure changes are visible on other processors. + */ +static __inline__ void __clear_bit(int nr, volatile void * addr) +{ + __asm__ __volatile__( + "btrl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +} + + + + diff -NaurbB rtlinux-3.2-pre1.old/rtl_malloc/Makefile rtlinux-3.2-pre1/rtl_malloc/Makefile --- rtlinux-3.2-pre1.old/rtl_malloc/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/rtl_malloc/Makefile 2003-07-17 11:02:02.000000000 +0200 @@ -0,0 +1,15 @@ +all: malloc.o +main: all + +include ../rtl.mk + +malloc.o: rtl_malloc.o + cp -f rtl_malloc.o ../modules/ + +clean: +# rm -f arch + find . \( -name '*~' -o -name '*.o' -o -name core \) -exec /bin/rm -r '{}' \; + +.PHONY: dummy + +include $(RTL_DIR)/Rules.make diff -NaurbB rtlinux-3.2-pre1.old/rtl_malloc/rtl_malloc.c rtlinux-3.2-pre1/rtl_malloc/rtl_malloc.c --- rtlinux-3.2-pre1.old/rtl_malloc/rtl_malloc.c 1970-01-01 01:00:00.000000000 +0100 +++ rtlinux-3.2-pre1/rtl_malloc/rtl_malloc.c 2003-07-17 11:02:02.000000000 +0200 @@ -0,0 +1,970 @@ +/* + * Doubly indexed dynamic memory allocator (DIDMA) + * Version 1.0 + * + * Written by Miguel Masmano Tello + * Copyright (C) Dec, 2002 OCERA Consortium + * Release under the terms of the GNU General Public License Version 2 + * + */ + +#include +#include "arch/bits.h" + +// linux/types.h includes definitions +// for the standard types +#include + +#if !defined (__RTL__) && defined (__KERNEL__) +#error "This modules can only be used by RTLinux or by user space" +#endif + +#if defined (__RTL__) + +#include + +#define INIT_THREAD_MUTEX() +#define THREAD_LOCK() __asm__ __volatile__ ("cli"); +#define THREAD_UNLOCK() __asm__ __volatile__ ("sti"); + +MODULE_AUTHOR("Miguel Masmano Tello "); +MODULE_DESCRIPTION("Doubly Indexed Memory Allocator (DIDMA) V1.0"); + +MODULE_LICENSE("GPL"); + +static int max_size = 1024; // 1 MByte + +MODULE_PARM(max_size, "i"); +MODULE_PARM_DESC(max_size, "Memory pool size in Kb (default=1024)"); + +static unsigned char *ptr_mem; + +/* This DIDMA version only can be used with BIGPHYSAREA patch */ +#if defined(CONFIG_BIGPHYSAREA) || defined(CONFIG_BIGPHYS_AREA) +#include +#else +#error BIGPHYSAREA PATCH MUST BE INSTALLED +#endif + +int init_module(void){ + // First of all we reserve the memory that will be used later + ptr_mem = (unsigned char *) bigphysarea_alloc(max_size * 1024); + if (ptr_mem == NULL) { + rtl_printf ("rtl_malloc PANIC: Error reserving memory!!"); + return -1; + } + if (init_memory_pool (max_size, 5, ptr_mem) < 0) return -1; + associate_buffer (ptr_mem); + + return 0; +} + +void cleanup_module(void){ + destroy_memory_pool(ptr_mem); + bigphysarea_free((caddr_t) ptr_mem, 0); +} + +#else // #if defined (__RTL__) + +#define INIT_THREAD_MUTEX() +#define THREAD_LOCK() +#define THREAD_UNLOCK() + +#endif // #if defined (__RTL__) + +/* + * The following TAD will be a double level indexed array, the most + * important thing is that the time is bounded, the reason of this is + * because DIDMA has been designed to be used by real time programs. + * + * First level Second level + * it is indexed it is indexed by 2**n+(2**n/m*index_number) + * by power of 2 + * 0 1 m-1 m + * ----> NULL --> NULL ----> NUL + * | | | + * ------- ---------------------...--------------------- + * 2**n | n | -----> |2**n+(2**n/m*0)|...| |...|2**n+(2**n/m*m)| + * |-----| ---------------------...--------------------- + * 2**n-1| n-1 | -----> .... | + * |-----| --->NULL + * ..... + */ + +/* + * Some defaults values; + * please, don't touch these macros + */ + +#define MIN_LOG2_SIZE 4 +#define MIN_SIZE (1 << MIN_LOG2_SIZE) +#define MAX_LOG2_SIZE 32 // 4 GBytes I think that this size is too much +//#define MAX_SL_INDEX (1 << MAX_SL_LOG2_INDEX) + +/* + * The following structure defines the pointers used + * by the header to know the position of the free blocks + */ + +typedef struct free_ptr_struct { + struct beg_block_header_struct *prev; + struct beg_block_header_struct *next; + + /* + * first_index and second_index are used to store + * mapping_function results, that's how we get some extra + * nanoseconds + */ + __u8 first_index; + __u8 second_index; +} free_ptr_t; + +/* + * BLOCK_USED must be used like mask with the magic number + * i.e. + * if ((magic_number & BLOCK_USED) = BLOCK_USED) then + * return USED; + * else + * return FREE + * end if; + */ + +#define BLOCK_USED 0x80000000 +#define BLOCK_FREE ~BLOCK_USED //0x7FFFFFFF + +#define LAST_BLOCK 0x40000000 +#define NOT_LAST_BLOCK ~LAST_BLOCK //0xBFFFFFFF + +/* + * The magic number must be calculated like: + * if ((magic_number & MAGIC_NUMBER) = MAGIC_NUMBER) then + * return OK; + * else + * return ERROR; + * end if; + */ + +#define MAGIC_NUMBER 0x2A59FA59 + +typedef struct beg_block_header_struct { + /* + * MAGIC_NUMBER is a sanity byte and it also codifies if + * the block is used or free + */ + __u32 magic_number; + + /* The size of the block in bytes */ + __u32 size; + + /* + * This pointer is used in order to have + * a quick access to the end of the block + */ + struct end_block_header_struct *block_tail; + + union { + struct free_ptr_struct free_ptr; + __u8 buffer[sizeof(struct free_ptr_struct)]; + } ptr; + +} beg_block_header_t; + +// This is a pointer to the head of the block +typedef struct end_block_header_struct { + beg_block_header_t *block_header; +} end_block_header_t; + +/* first level index array */ +typedef struct fl_array_struct { + /* ptr is pointer to next level */ + beg_block_header_t **sl_array; + + /* bitmapSL is the second level bitmap */ + __u32 bitmapSL; +} fl_array_t; + +/* + * When the user calls init_memory_pool, he must give a block of memory + * block, this block will be used to store the DIDMA structure + */ + +typedef struct DIDMA_struct { + __u32 magic_number; + /* + * max_fl_index, max_sl_index and max_sl_log2_index + * must be __u8 but the compiler assigns 32 bits by efficiency, + * we also do that + */ + __u32 max_fl_index; + __u32 max_fl_pow2_index; + __u32 max_sl_index; + __u32 max_sl_log2_index; + /* bitmapFL is the bitmap of the first level */ + __u32 bitmapFL; + __s32 total_size; + /* first_bh will be our first memory block allocated by MALLOC function */ + beg_block_header_t *first_bh; + beg_block_header_t *memory_pool; + + /* + * fl_array will be our first level array, + * it will be an array of [max_fl_index] elements + */ + fl_array_t *fl_array; +} DIDMA_t; + +/* + * header_overhead has size of blocks_header - 2 * ptr to next free block + */ +static __s32 beg_header_overhead = 0, end_header_overhead = 0; + +#define DIDMA__set_bit(num, mem) mem |= (1 << num) +#define DIDMA__clear_bit(num, mem) mem &= ~(1 << num) + +char *main_buffer = NULL; + +/* + * log2size () returns cell of log2 (len) it does a search between + * MIN_SIZE and MAX_SIZE values in order to find the log2 of the size. + * Theorically we have obtained that this method is more efficient + * than the asm instruction which does the same operation + */ + +static inline __s32 log2size (size_t size, size_t *new_size) { + + __s32 i; + + if (size <= 0) { + *new_size = -1; + return -1; + } + + if (size <= MIN_SIZE){ + *new_size = MIN_SIZE; + return MIN_LOG2_SIZE; + } + + /* One method in order to find log2 of a given number */ + /*-----------------*/ + /* + for (i = MIN_LOG2_SIZE; + (i <= MAX_LOG2_SIZE) && (size > (*new_size = (1 << i))) ; i++); + */ + /*-----------------*/ + + /* Other method more machine dependent */ + /*------------------------------*/ + i = DIDMA_fls(size); + + i = ((1 << i) != size )? ++i: i; + + *new_size = (1 << i); + + if (i < MIN_LOG2_SIZE) { + *new_size = MIN_SIZE; + return MIN_LOG2_SIZE; + } + + /*----------------------------*/ + + if (i > MAX_LOG2_SIZE) { + return -1; + } + + return i; +} + +/* + * mapping_function () returns first and second level index + * + * first level index function is: + * fl = log2 (size) + * + * and second level index function is: + * sl = (size - 2**(log2size (size))) / (log2 (size) - log2 (MAX_SL_INDEX)) + * + */ + +static inline __s32 mapping_function (size_t size, __s32 *fl, __s32 *sl, + DIDMA_t *ptr_DIDMA){ + __s32 aux, new_len; + + // first level = log2 (size) + *fl = log2size (size, &new_len); + + if (new_len == size) { + // if 2**fl == size, second level must be 0 + *sl = 0; + } else { + -- *fl; + aux = *fl - ptr_DIDMA -> max_sl_log2_index; + if (aux >= 0) + *sl = (int)((size - (new_len >> 1)) >> aux); + else + *sl = (int)(size - (new_len >> 1)); + } + + return 0; +} + +// max_size is in Kbytes +int init_memory_pool (int max_size, + int max_sl_log2_index, char *block_ptr) { + __s32 n, free_mem = 0; + + end_block_header_t *header_end; + __s32 size_fl_sl_array, i; + DIDMA_t *ptr_DIDMA; + + if (!(max_size > 0)) { + PRINT_MSG ("ERROR: size must be > 0\n"); + return -1; + } + INIT_THREAD_MUTEX(); + //if ((int) max_sl_log2_index > MIN_LOG2_SIZE) { + // PRINT_MSG ("ERROR: max_sl_log2_index (%d) must be < %d\n", + // max_sl_log2_index, MIN_LOG2_SIZE); + // return -1; + //} + + if (max_sl_log2_index <= 0) { + PRINT_MSG ("ERROR: max_sl_log2_index (%d) must be >= 0\n", + max_sl_log2_index); + return -1; + } + + memset ((char *) block_ptr, 0, max_size * 1024); + + ptr_DIDMA = (DIDMA_t *) block_ptr; + + ptr_DIDMA -> magic_number = MAGIC_NUMBER; + /* Total size of the block, DIDMA_struct + free_memory */ + ptr_DIDMA -> total_size = max_size * 1024; + ptr_DIDMA -> max_sl_log2_index = max_sl_log2_index; + ptr_DIDMA -> max_sl_index = (1 << ptr_DIDMA -> max_sl_log2_index); + + size_fl_sl_array = (__s32) sizeof (fl_array_t) + + ((__s32) sizeof (beg_block_header_t *) + * (__s32) ptr_DIDMA -> max_sl_index); + + + free_mem = ptr_DIDMA -> total_size + - sizeof (DIDMA_t) + - size_fl_sl_array; + + for (n = MIN_LOG2_SIZE + 1; + ((int) free_mem - (int) size_fl_sl_array) > (1< max_fl_index = n; + ptr_DIDMA -> max_fl_pow2_index = (1 << ptr_DIDMA -> max_fl_index); + + n -= MIN_LOG2_SIZE; + + /* max_fl_index will never be greater than MAX_FL_INDEX */ + if (ptr_DIDMA -> max_fl_index < 0 || MAX_FL_INDEX < 0) return -1; + + ptr_DIDMA -> fl_array = ( fl_array_t *) + ((__u32) &(ptr_DIDMA -> fl_array) + + (__u32) sizeof (ptr_DIDMA -> fl_array)); + + + for (i = 0 ; i < n; i ++) + ptr_DIDMA -> fl_array [i] .sl_array = (beg_block_header_t **) + (((__s32) ptr_DIDMA -> fl_array + ((__s32) sizeof (fl_array_t) * n)) + + ((__s32) sizeof (beg_block_header_t *) * + (__s32) ptr_DIDMA -> max_sl_index * i)); + + ptr_DIDMA -> memory_pool = (beg_block_header_t *) + ((__u32) ptr_DIDMA -> fl_array + + (size_fl_sl_array * n)); + + ptr_DIDMA -> first_bh = ptr_DIDMA -> memory_pool; + + beg_header_overhead = (int) (ptr_DIDMA -> memory_pool -> ptr.buffer) + - (int) ptr_DIDMA -> memory_pool; + + end_header_overhead = sizeof (end_block_header_t); + + ptr_DIDMA -> bitmapFL = 0; + + /* memory_pool initialization */ + + // the block is free + ptr_DIDMA -> memory_pool -> magic_number = MAGIC_NUMBER | LAST_BLOCK; + ptr_DIDMA -> memory_pool -> size = + free_mem - beg_header_overhead - end_header_overhead; + ptr_DIDMA -> memory_pool -> ptr.free_ptr.prev = NULL; + ptr_DIDMA -> memory_pool -> ptr.free_ptr.next = NULL; + + header_end = (end_block_header_t *) + (((__u32) ptr_DIDMA -> memory_pool -> ptr.buffer) + + (__u32) ptr_DIDMA -> memory_pool -> size); + + header_end -> block_header = ptr_DIDMA -> memory_pool; + ptr_DIDMA -> memory_pool -> block_tail = header_end; + return ptr_DIDMA -> memory_pool -> size; +} + +void destroy_memory_pool (char *block_ptr) { + DIDMA_t *ptr_DIDMA; + ptr_DIDMA = (DIDMA_t *) block_ptr; + ptr_DIDMA -> magic_number = 0; +} + +/* see man malloc */ +/* + * malloc searchs a free block of size 'size', + * after the free block will be splitted in two new blocks, + * one of these new blocks will be given to the user and the + * other will be inserted into DIDMA structure + * + * The cost of this operation is + * best case: (K) = (1) + * worst case: (MAX_FL_LOG2_INDEX - MIN_FL_LOG2_INDEX + MAX_SL_INDEX + K) + * = (1) + * where K is a constant integer + */ + +#ifdef WITH_RTL_PREFIX +void *rtl_malloc_ex (size_t size, char *block_ptr) { +#else +void *malloc_ex (size_t size, char *block_ptr) { +#endif + DIDMA_t *ptr_DIDMA; + + int for_free_block = 0, fl, sl, n, found = 0; + beg_block_header_t *bh = NULL, *bh2 = NULL; + end_block_header_t *e_bh = NULL, *e_bh2 = NULL; + + ptr_DIDMA = (DIDMA_t *) block_ptr; + + if (ptr_DIDMA == NULL || ptr_DIDMA -> magic_number != MAGIC_NUMBER) { + PRINT_MSG ("FATAL ERROR: DIDMA structure not initialized\n"); + return NULL; + } + + if (!(size > 0)) { + PRINT_MSG ("ERROR: Memory pool exhausted!!!\n"); + return NULL; + } + + if (size <= MIN_SIZE) { + size = MIN_SIZE; + fl = 0; + sl = 0; + } else { + + mapping_function (size, &fl, &sl, ptr_DIDMA); + + if (++sl == ptr_DIDMA -> max_sl_index) { + fl ++; + sl = 0; + } + + /* + * This is the reason of the internal fragmentation + * The block given is greater that the size demanded + */ + size = (1 << fl); + + /* size can be smaller that maximum SLI, in this case the mapping function + has problems calculating fl and sl values */ + if (size < (1 << ptr_DIDMA -> max_sl_log2_index)) + size = size + ((size >> MIN_LOG2_SIZE) * sl); + else + size = size + ((size >> ptr_DIDMA -> max_sl_log2_index) * sl); + + fl -= MIN_LOG2_SIZE; + } + + /*----------------------------------------*/ + /* The search for a free block begins now */ + /*----------------------------------------*/ + + /* + * Our first try, we take the first free block + * from fl_array or its buddy + */ + THREAD_LOCK(); + sl = ptr_DIDMA -> fl_array[fl].bitmapSL & ((~0) << sl); + if (sl != 0) { + sl = DIDMA_fls(sl); + bh = ptr_DIDMA -> fl_array [fl].sl_array [sl]; + ptr_DIDMA -> fl_array [fl].sl_array [sl] = bh -> ptr.free_ptr.next; + if (ptr_DIDMA -> fl_array [fl].sl_array [sl] != NULL) + ptr_DIDMA ->fl_array [fl].sl_array [sl] -> ptr.free_ptr.prev = NULL; + else { + DIDMA__clear_bit (sl, ptr_DIDMA -> fl_array[fl].bitmapSL); + if (!ptr_DIDMA -> fl_array[fl].bitmapSL) + DIDMA__clear_bit (fl, ptr_DIDMA -> bitmapFL); + } + found = 1; + goto out; + } + + /* + * if fl_array is empty we will take a free block + * from free_block pointer + */ + + if (ptr_DIDMA -> memory_pool != NULL && + ptr_DIDMA -> memory_pool -> size >= size) { + bh = ptr_DIDMA -> memory_pool; + ptr_DIDMA -> memory_pool = NULL; + for_free_block = 1; + found = 1; + goto out; + } + + /* + * On the last case a free block is searched using a bitmap + */ + + fl = DIDMA_fls(ptr_DIDMA -> bitmapFL & ((~0) << (fl + 1))); + + if (fl > 0) { + sl = DIDMA_fls(ptr_DIDMA -> fl_array[fl].bitmapSL); + bh = ptr_DIDMA -> fl_array [fl].sl_array [sl]; + ptr_DIDMA -> fl_array [fl].sl_array [sl] = bh -> ptr.free_ptr.next; + if (ptr_DIDMA -> fl_array [fl].sl_array [sl] != NULL){ + ptr_DIDMA -> fl_array [fl].sl_array [sl] + -> ptr.free_ptr.prev = NULL; + } else { + DIDMA__clear_bit (sl, ptr_DIDMA -> fl_array[fl].bitmapSL); + if (!ptr_DIDMA -> fl_array[fl].bitmapSL) + DIDMA__clear_bit (fl, ptr_DIDMA -> bitmapFL); + } + found = 1; + goto out; + } + /* end of the search */ + /*------------------------------------------------------------*/ + + out: + + /* + * HUGGGG, NOT ENOUGHT MEMORY + * I think that we have done all that we have been able, I'm sorry + */ + + if (!found) { + THREAD_UNLOCK(); + PRINT_MSG ("ERROR: Memory pool exhausted!!!\n"); + return NULL; + } + + /* + * we can say: YESSSSSSSSSSS, we have enought memory!!!! + */ + + /* can bh be splitted? */ + n = (int)(bh -> size - size - beg_header_overhead - end_header_overhead); + if (n >= (int) MIN_SIZE) { + /* + * Yes, bh will be splitted + */ + /* The new block will begin at the end of the current block */ + bh -> size = size; + e_bh = (end_block_header_t *) ((__u8 *) (bh -> ptr.buffer) + bh -> size); + + bh -> block_tail = e_bh; + + + e_bh -> block_header = bh; + + bh2 = (beg_block_header_t *) ((__u8 *) bh -> ptr.buffer + size + + end_header_overhead); + + + bh2 -> magic_number = bh -> magic_number; + bh -> magic_number = MAGIC_NUMBER | BLOCK_USED; + + bh2 -> size = n; + e_bh2 = (en