diff -BNru rt_orig/doc/Configure.help rt_with_timers/doc/Configure.help --- rt_orig/doc/Configure.help 2003-04-01 20:46:27.000000000 -0800 +++ rt_with_timers/doc/Configure.help 2003-04-01 20:46:27.000000000 -0800 @@ -27,7 +27,7 @@ # your own kernel configuration tools. The texts are copyrighted (c) # 1995-1999 by Axel Boldt and many others and are governed by the GNU # General Public License. - + POSIX Style IO CONFIG_RTL_POSIX_IO This allows POSIX style IO operations inside of RTLinux. @@ -100,16 +100,19 @@ install signal handlers, among other things. Signals are in determinated cases a good interprocess communication mechanism. +POSIX timers +CONFIG_OC_PTIMERS + POSIX timers allows a mechanism that can notify a thread when + the time as measured by a particular clock has reached or passed + a specified value, or when a specified amount of time has passed. + Facilities supported by POSIX timers that are desirable for + real-time operating systems: + - Support for additional clocks. + - Allowance for greater time resolution (modern timers are + capable of nanosecond resolution; the hardware should support it) + - Ability to use POSIX Signals to indicate timer expiration. - - - - - - - - - + POSIX timers deppends on POSIX signals. diff -BNru rt_orig/examples/Makefile rt_with_timers/examples/Makefile --- rt_orig/examples/Makefile 1969-12-31 16:00:00.000000000 -0800 +++ rt_with_timers/examples/Makefile 2003-04-01 20:46:29.000000000 -0800 @@ -0,0 +1,34 @@ +all: sched_bug.o mutex_bug.o timespec_add_ns_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 + +timespec_add_ns_bug.o: timespec_add_ns_bug.c + $(CC) ${INCLUDE} ${CFLAGS} -c timespec_add_ns_bug.c -g -o timespec_add_ns_bug_tmp.o + $(LD) $(LDFLAGS) -r -o timespec_add_ns_bug.o timespec_add_ns_bug_tmp.o ${LIBGCC} +clean: + rm -f *.o + + + + + + + + diff -BNru rt_orig/examples/README rt_with_timers/examples/README --- rt_orig/examples/README 2003-04-01 20:46:27.000000000 -0800 +++ rt_with_timers/examples/README 2003-04-01 20:46:29.000000000 -0800 @@ -1,22 +1,90 @@ -To run the examples, you have to compile and install the main RTLinux modules. -Please, See ../INSTALL. -examples: +Scheduler BUG 6-11-02: -hello -- the "Hello World" program in realtime -hello_dev_mem -- Hello World expanded to use /dev/mem to share data - with user-space -hello_mbuff -- Hello World again... this time using mbuff -parallel -- some examples using the parallelport for I/O -v1api -- RTLinux version 1 API examples -fp -- using floating point in RTLinux -cpp -- using C++ in rt-context (you don't want to do that....) -frank -- using FIFOs, multithreaded-rt and controling threads via rtfifos -measurements -- measuring scheduling precision and other performance parameters -kernel_resources -- examples of sharing resources between kernel-space, - user-space and rt-threads. -mutex -- using synchronization primitives -sound -- handling interrupts in Real-Time -new_thread -- creating threads from within rt-context -old -- old stuff -signals -- POSIX signals test programs \ No newline at end of file + 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_suspend_np, pthread_wakeup_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. + 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.). 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 storing 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. + +timespec_add_ns BUG 22-11-02 +The macro timespec_add-ns available in include/rtl_time.h is implemented as: +#define old_timespec_add_ns(t,n) do { \ + (t)->tv_nsec += n; \ + timespec_normalize(t); \ +} while (0) +and timespec_normalize is implemented as: + #define timespec_normalize(t) {\ + if ((t)->tv_nsec >= NSECS_PER_SEC) { \ + (t)->tv_nsec -= NSECS_PER_SEC; \ + (t)->tv_sec++; \ + } else if ((t)->tv_nsec < 0) { \ + (t)->tv_nsec += NSECS_PER_SEC; \ + (t)->tv_sec--; \ + } \ + } + +What should happen if the result of (t)->tv_nsec += n; is bigger than two seconds. Clearly, +this will lead to an invalid time specification having tv_nsec field a value bigger of +NSECS_PER_SEC (1000*1000*1000). Also overflow could happen if the result is bigger than +2^31 ( 2147483648 ). + +The alternative solution is to implement timespec_normalize as: + +#define TWOSECONDS (NSECS_PER_SEC*2) +#define timespec_add_ns(t,n) do { \ + long long aux=(t)->tv_nsec+(n);\ + \ + if ((aux > TWOSECONDS) || (aux < -TWOSECONDS)) /*check overflow*/ {\ + (t)->tv_nsec +=((n) % NSECS_PER_SEC) ; \ + (t)->tv_sec += ((n) / NSECS_PER_SEC); \ + } else { (t)->tv_nsec=aux; }\ + \ + timespec_normalize(t); \ +} while (0) + +The file timespec_add_ns placed in the dirtory examples/bug tests the +both implementations. diff -BNru rt_orig/examples/bug/Makefile rt_with_timers/examples/bug/Makefile --- rt_orig/examples/bug/Makefile 2003-04-01 20:46:29.000000000 -0800 +++ rt_with_timers/examples/bug/Makefile 1969-12-31 16:00:00.000000000 -0800 @@ -1,31 +0,0 @@ -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 -BNru rt_orig/examples/bug/README rt_with_timers/examples/bug/README --- rt_orig/examples/bug/README 2003-04-01 20:46:29.000000000 -0800 +++ rt_with_timers/examples/bug/README 1969-12-31 16:00:00.000000000 -0800 @@ -1,74 +0,0 @@ -/* - * 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 -BNru rt_orig/include/posix/time.h rt_with_timers/include/posix/time.h --- rt_orig/include/posix/time.h 2003-03-01 03:46:37.000000000 -0800 +++ rt_with_timers/include/posix/time.h 2003-04-01 20:46:27.000000000 -0800 @@ -61,5 +61,68 @@ return ts.tv_sec; } +#ifdef CONFIG_OC_PTIMERS +#include #endif +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -BNru rt_orig/include/rtl_sched.h rt_with_timers/include/rtl_sched.h --- rt_orig/include/rtl_sched.h 2003-04-01 20:46:27.000000000 -0800 +++ rt_with_timers/include/rtl_sched.h 2003-04-01 20:46:27.000000000 -0800 @@ -42,10 +42,6 @@ #define rtl_sched_param sched_param #define TIMER_ABSTIME 1 -#define RTL_MAX_TIMERS 32 - - -typedef struct rtl_timer_struct *timer_t; struct rtl_cleanup_struct { void (*routine)(void*); @@ -117,6 +113,8 @@ #define RTL_SIGUSR2 (RTL_SIGUSR1+1) #define RTL_SIGRTMIN (RTL_SIGUSR2+1) #define RTL_SIGRTMAX RTL_MAX_SIGNAL +#define RTL_SIG_DFL 0 +#define RTL_SIG_IGN 0 #endif /*TODO How will this work on PPC */ diff -BNru rt_orig/include/rtl_time.h rt_with_timers/include/rtl_time.h --- rt_orig/include/rtl_time.h 2003-03-01 03:46:37.000000000 -0800 +++ rt_with_timers/include/rtl_time.h 2003-04-01 20:46:27.000000000 -0800 @@ -5,6 +5,8 @@ * * Copyright (C) 1999 Michael Barabanov * + * Fixed overflow in timespec_add_ns Josep Vidal (OCERA) + * */ #ifndef __RTL_TIME__ @@ -96,16 +98,15 @@ #endif #endif /* __KERNEL__ */ - /* convenience functions */ #define timespec_normalize(t) {\ - if ((t)->tv_nsec >= NSECS_PER_SEC) { \ - (t)->tv_nsec -= NSECS_PER_SEC; \ - (t)->tv_sec++; \ - } else if ((t)->tv_nsec < 0) { \ - (t)->tv_nsec += NSECS_PER_SEC; \ - (t)->tv_sec--; \ - } \ + if ((t)->tv_nsec >= NSECS_PER_SEC) { \ + (t)->tv_nsec -= NSECS_PER_SEC; \ + (t)->tv_sec++; \ + } else if ((t)->tv_nsec < 0) { \ + (t)->tv_nsec += NSECS_PER_SEC; \ + (t)->tv_sec--; \ + } \ } #define timespec_add(t1, t2) do { \ @@ -120,11 +121,18 @@ timespec_normalize(t1);\ } while (0) +#define TWOSECONDS (NSECS_PER_SEC*2) #define timespec_add_ns(t,n) do { \ - (t)->tv_nsec += (n); \ - timespec_normalize(t); \ - } while (0) - + long long aux=(t)->tv_nsec+(n);\ + \ + if ((aux > TWOSECONDS) || (aux < -TWOSECONDS)) /*check overflow*/ {\ + (t)->tv_nsec +=((n) % NSECS_PER_SEC) ; \ + (t)->tv_sec += ((n) / NSECS_PER_SEC); \ + } else { (t)->tv_nsec=aux; }\ + \ + timespec_normalize(t); \ +} while (0) + #define timespec_nz(t) ((t)->tv_sec != 0 || (t)->tv_nsec != 0) #define timespec_lt(t1, t2) ((t1)->tv_sec < (t2)->tv_sec || ((t1)->tv_sec == (t2)->tv_sec && (t1)->tv_nsec < (t2)->tv_nsec)) diff -BNru rt_orig/schedulers/Makefile rt_with_timers/schedulers/Makefile --- rt_orig/schedulers/Makefile 2003-03-01 03:46:38.000000000 -0800 +++ rt_with_timers/schedulers/Makefile 2003-04-01 20:46:27.000000000 -0800 @@ -1,6 +1,6 @@ # (c) Victor Yodaiken 1998, Released under GPL -all: rtl_time.o rtl_sched.o +all: rtl_time.o rtl_timer.o rtl_sched.o clean: rm -f *.o @@ -23,8 +23,8 @@ depend: rtl_sched.o $(CC) ${INCLUDE} ${CFLAGS} -M rtl_sched.c > .depends -rtl_sched.o: rtl_sched_tmp.o switch.o sw.o rtl_mutex.o unistd.o signal.o rtl_sema.o rtl_posix.o $(LIBGCC) - $(LD) $(LDFLAGS) -r -o rtl_sched.o rtl_sched_tmp.o switch.o sw.o rtl_mutex.o unistd.o signal.o rtl_sema.o rtl_posix.o -static ${LIBGCC} +rtl_sched.o: rtl_sched_tmp.o switch.o sw.o rtl_mutex.o unistd.o signal.o rtl_sema.o rtl_posix.o rtl_timer.o $(LIBGCC) + $(LD) $(LDFLAGS) -r -o rtl_sched.o rtl_sched_tmp.o switch.o sw.o rtl_mutex.o unistd.o signal.o rtl_sema.o rtl_posix.o rtl_timer.o -static ${LIBGCC} cp -f rtl_sched.o ../modules/ rtl_sched_tmp.o: rtl_sched.c ../include/rtl_sched.h @@ -49,6 +49,9 @@ $(LD) -r -o rtl_time.o rtl_time_tmp.o rtl_time_common.o $(LIBGCC) cp -f rtl_time.o ../modules +rtl_timer.o: rtl_timer.c ../include/rtl_timer.h + $(CC) ${INCLUDE} ${CFLAGS} -o rtl_timer.o -c rtl_timer.c + install: rtl_sched.o install -c -m 644 rtl_sched.o ${RTL_DIR}/modules diff -BNru rt_orig/schedulers/rtl_sched.c rt_with_timers/schedulers/rtl_sched.c --- rt_orig/schedulers/rtl_sched.c 2003-04-01 20:46:27.000000000 -0800 +++ rt_with_timers/schedulers/rtl_sched.c 2003-04-01 20:46:27.000000000 -0800 @@ -3,8 +3,8 @@ large numbers of tasks. I think that large numbers of tasks requires a total redesign of scheduler and that the scheduler should optimize for < 40 threads and really for <10 - - */ + +*/ /* * RTLinux default scheduler * RTLinux has a modular scheduler and this may be replaced if desired. @@ -14,6 +14,7 @@ * Released under the terms of the GNU General Public License Version 2 * * Added user signals support - Dec, 2002 Josep Vidal (OCERA) + * Added POSIX timers support - Dec, 2002 Josep Vidal (OCERA) * * Fixed stack overflow when sending RTL_SIGNAL_SUSPEND signal. J. Vidal (OCERA) * Fixed mutex bug when setting t->do_abort=0 on do_signal. J. Vidal (OCERA) @@ -42,7 +43,9 @@ #include #include #include - +#ifdef CONFIG_OC_PTIMERS +#include +#endif static spinlock_t rtl_tqueue_lock; static int rtl_sched_irq; @@ -156,7 +159,7 @@ } set_bit(signal, &thread->pending); #ifdef CONFIG_OC_PSIGNALS - if ((signal >= RTL_SIGUSR1) && HIGHER_PRIORITY_THREAD(thread,pthread_self())) rtl_schedule(); + if ((signal >= RTL_SIGUSR1) && HIGHER_PRIORITY_THREAD(thread,pthread_self())) rtl_schedule(); #endif return 0; } else if(thread != rtl_get_linux_thread(rtl_getcpuid())) { @@ -344,38 +347,47 @@ return 0; } +inline static hrtime_t find_preemptor(schedule_t *s, struct rtl_thread_struct *chosen){ + struct rtl_thread_struct *t; + struct rtl_thread_struct *preemptor=0; +#ifdef CONFIG_OC_PTIMERS + timer_t timer =0; + hrtime_t preempt_time=HRTIME_INFINITY; +#endif + + for (t = s->rtl_tasks; t; t = t->next) { + if (test_bit(RTL_THREAD_TIMERARMED, &t->threadflags)) { + if (t->sched_param.sched_priority > chosen->sched_param.sched_priority) + { + if(!preemptor ||(t->resume_time < preemptor->resume_time)) + { + preemptor = t; + } + } + } + } -/* TODO */ -int timer_gettime(timer_t timerid, struct itimerspec *value) -{ - return EINVAL; -} - -/* TODO */ -int timer_getoverrun(timer_t timerid) -{ - return EINVAL; -} - - - -inline static struct rtl_thread_struct * find_preemptor(schedule_t *s, struct rtl_thread_struct *chosen){ - struct rtl_thread_struct *t; - struct rtl_thread_struct *preemptor=0; - for (t = s->rtl_tasks; t; t = t->next) { - if (test_bit(RTL_THREAD_TIMERARMED, &t->threadflags)) { - if (t->sched_param.sched_priority > chosen->sched_param.sched_priority) - { - if(!preemptor ||(t->resume_time < preemptor->resume_time)) - { - preemptor = t; - } - } - } +#ifdef CONFIG_OC_PTIMERS + if (preemptor) preempt_time=preemptor->resume_time; + for (timer=get_timer_list_start();timer;timer=timer->next){ + // find preemptor. + if (timer->owner->sched_param.sched_priority > chosen->sched_param.sched_priority){ + if( TIMER_ARMED(timer)){ + if (timer->expires.it_value < preempt_time) { + preempt_time = timer->expires.it_value; } - return preemptor; + } + } else { /* timer list is ordered by owner priority */ + break; + } + } + return (preempt_time!=HRTIME_INFINITY)? preempt_time : 0 ; +#endif + + return (preemptor)? preemptor->resume_time : 0 ; } + #define do_abort(t) do { clear_bit(RTL_THREAD_TIMERARMED, &t->threadflags); if (t->abort) { t->abort(t->abortdata);}} while (0) @@ -395,10 +407,10 @@ rtl_irqstate_t flags; rtl_no_interrupts(flags); - if (test_and_clear_bit(RTL_SIGNAL_SUSPEND, &t->pending)) { - /* t->abort = 0; - t->abortdata = 0; - */ + if (test_and_clear_bit(RTL_SIGNAL_SUSPEND, &t->pending)) { + /* t->abort = 0; + t->abortdata = 0; + */ do_abort(t); RTL_MARK_SUSPENDED(t); } @@ -433,7 +445,7 @@ for (sig=RTL_MAX_SIGNAL;sig>=RTL_SIGUSR1;sig--){ if (test_bit(sig,&t->pending) && !test_bit(sig,&t->blocked)){ - + if (rtl_sigact[sig].owner==t){ fun=rtl_sigact[sig].sa_handler; if (fun) { @@ -449,8 +461,8 @@ if (test_and_clear_bit(RTL_THREAD_SIGNAL_INTERRUMPIBLE,&t->threadflags)){ pthread_kill(t,RTL_SIGNAL_WAKEUP); } - clear_bit (RTL_SCHED_TIMER_OK, &LOCAL_SCHED->sched_flags); } + clear_bit (RTL_SCHED_TIMER_OK, &LOCAL_SCHED->sched_flags); } /* The bit should be pending until unblocked. */ clear_bit(sig,&t->pending); @@ -465,11 +477,14 @@ schedule_t *sched; struct rtl_thread_struct *t; struct rtl_thread_struct *new_task; - struct rtl_thread_struct *preemptor = 0; + hrtime_t preempt_time = 0; unsigned long interrupt_state; int cpu_id = rtl_getcpuid(); hrtime_t now; rtl_sigset_t mask; +#ifdef CONFIG_OC_PTIMERS + timer_t timer = 0; +#endif idle: rtl_no_interrupts(interrupt_state); rtl_trace2 (RTL_TRACE_SCHED_IN, (long) pthread_self()); @@ -484,6 +499,15 @@ sched->clock->value = now; } +#ifdef CONFIG_OC_PTIMERS + for (timer=get_timer_list_start();timer;timer=timer->next){ + if (timer_expiration(timer,now,sched->clock->mode)){ + expiration_notification(timer); + UPDATE_TIMER(timer); + } + } +#endif + for (t = sched->rtl_tasks; t; t = t->next) { /* expire timers */ @@ -520,8 +544,8 @@ } if (sched->clock->mode == RTL_CLOCK_MODE_ONESHOT && !test_bit (RTL_SCHED_TIMER_OK, &sched->sched_flags)) { - if ( (preemptor = find_preemptor(sched,new_task))) { - (sched->clock)->settimer(sched->clock, preemptor->resume_time - now); + if ( (preempt_time = find_preemptor(sched,new_task))) { + (sched->clock)->settimer(sched->clock, preempt_time - now); } else { (sched->clock)->settimer(sched->clock, (HRTICKS_PER_SEC / HZ) / 2); } @@ -558,10 +582,11 @@ __save_flags(flags); __restore_flags(flags); }*/ - mask = pthread_self()->pending; - rtl_restore_interrupts(interrupt_state); - if (pthread_self()->pending & ~(1 << RTL_SIGNAL_READY)) do_signal(pthread_self()); + mask = pthread_self()->pending; + rtl_restore_interrupts(interrupt_state); + if (pthread_self()->pending & ~(1 << RTL_SIGNAL_READY)) do_signal(pthread_self()); + #ifdef CONFIG_OC_PSIGNALS /* Signal handlers are non re-entrant, i.e. first finish current handler execution and then manage the rest of pending signals. */ @@ -930,6 +955,9 @@ schedule_t *s; unsigned int cpu_id = rtl_getcpuid(); +#ifdef CONFIG_OC_PTIMERS + rtl_spin_lock_init(&rtl_timer_list_lock); +#endif rtl_spin_lock_init (&rtl_tqueue_lock); zombie_threads = 0; ret = rtl_get_soft_irq (sched_irq_handler, "RTLinux Scheduler"); diff -BNru rt_orig/scripts/config.in rt_with_timers/scripts/config.in --- rt_orig/scripts/config.in 2003-04-01 20:46:27.000000000 -0800 +++ rt_with_timers/scripts/config.in 2003-04-01 20:46:28.000000000 -0800 @@ -39,6 +39,10 @@ bool 'Nolinux support (experimental)' CONFIG_RTL_RESERVE_CPU bool 'RTLinux tracer support (experimental)' CONFIG_RTL_TRACER bool 'POSIX Signals' CONFIG_OC_PSIGNALS +if [ "$CONFIG_OC_PSIGNALS" = "y" ]; then + bool 'POSIX Timers' CONFIG_OC_PTIMERS +fi + source main/arch/config.in endmenu