POSIX clocks & timers take 14 (NOT HIGH RES)
Subsystems (6)
PATCH 1/1 POSIX clocks & timers take 14 (NOT HIGH RES)
This patch has no configure options!
With this version I have changed the signal/ repeating timer model to avoid timer storms from repeating timers. The timer is not inserted back into the timer_list until the signal is dequeued by the receiving task. So, once a timer expires, it will cause NO further system overhead until the task takes the signal, regardless of the repeat interval. The POSIX standard allows this, (actually it seems to encourage it). Each timer has an "overrun" counter that keeps track of the number of times the signal should have been generated but was not because the prior signal was not yet picked up.
The timer_gettime() call returns the time as if the timer were in the timer_list so to the program it looks like it is, but the system overhead is nil.
The really nice thing about this way of limiting timer storms is that a really fast real time program can actually get the high turn over rate while not being impacted by slower, or blocked programs trying to do the same thing. Like wise, if a program loses the cpu, its timers will not impact other tasks. Many thanks to Mark Salisbury <[email protected]> for suggesting this.
The patch stands alone (i.e. does not require any of the following high-res patches).
This, patch implements the POSIX clocks and timers functions. The two standard clocks are defined(CLOCK_REALTIME & CLOCK_MONOTONIC).
Nano_sleep() is rolled into clock_nanosleep(). Also a bug fix in clock_nanosleep().
kernel/timer.c is modified to remove the timer_t typedef which conflicts with the POSIX standard definition for this type.
The patch introduces a new kernel source (posix-timers.c) which contains most of the code.
This implementation has no limits on the number of timers in the system or per process or task, thanks to Jim Houston.
Kernel version 2.5.49
Test programs, man pages and readme files as well as this patch are available on the sourceforge high-res-timers site:
http://sourceforge.net/projects/high-res-timers/
Please apply.
Signature · 5 lines
George Anzinger [email protected] High-res-timers: http://sourceforge.net/projects/high-res-timers/ Preemption patch: http://www.kernel.org/pub/linux/kernel/people/rml
arch/i386/kernel/entry.S +14 -8
@@ -41,7 +41,6 @@ */ #include <linux/config.h> -#include <linux/sys.h> #include <linux/linkage.h> #include <asm/thread_info.h> #include <asm/errno.h>
@@ -239,7 +238,7 @@ pushl %eax # save orig_eax SAVE_ALL GET_THREAD_INFO(%ebx) - cmpl $(NR_syscalls), %eax + cmpl $(nr_syscalls), %eax jae syscall_badsys # system call tracing in operation testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebx)
@@ -315,7 +314,7 @@ xorl %edx,%edx call do_syscall_trace movl ORIG_EAX(%esp), %eax - cmpl $(NR_syscalls), %eax + cmpl $(nr_syscalls), %eax jnae syscall_call jmp syscall_exit
@@ -769,8 +768,15 @@ .long sys_epoll_wait .long sys_remap_file_pages .long sys_set_tid_address - - - .rept NR_syscalls-(.-sys_call_table)/4 - .long sys_ni_syscall - .endr + .long sys_timer_create + .long sys_timer_settime /* 260 */ + .long sys_timer_gettime + .long sys_timer_getoverrun + .long sys_timer_delete + .long sys_clock_settime + .long sys_clock_gettime /* 265 */ + .long sys_clock_getres + .long sys_clock_nanosleep + + +nr_syscalls=(.-sys_call_table)/4
arch/i386/kernel/time.c +1 -0
@@ -132,6 +132,7 @@ time_maxerror =NTP_PHASE_LIMIT ; time_esterror =NTP_PHASE_LIMIT ;write_unlock_irq (&xtime_lock); +clock_was_set (); }/*
fs/exec.c +1 -0
@@ -778,6 +778,7 @@flush_signal_handlers (current);flush_old_files (current->files); +exit_itimers (current);return 0 ;
include/asm-generic/siginfo.h +12 -4
@@ -43,8 +43,11 @@/* POSIX.1b timers */ struct { -unsigned int _timer1; -unsigned int _timer2; +timer_t _tid;/* timer id */ +int _overrun;/* overrun count */ +char _pad[sizeof ( __ARCH_SI_UID_T) -sizeof (int )]; +sigval_t _sigval;/* same as below */ +int _sys_private;/* not to be passed to user */ } _timer;/* POSIX.1b signals */
@@ -86,8 +89,9 @@*/ #define si_pid _sifields._kill._pid#define si_uid _sifields._kill._uid -#define si_timer1 _sifields._timer._timer1 -#define si_timer2 _sifields._timer._timer2 +#define si_tid _sifields._timer._tid +#define si_overrun _sifields._timer._overrun +#define si_sys_private _sifields._timer._sys_private#define si_status _sifields._sigchld._status#define si_utime _sifields._sigchld._utime#define si_stime _sifields._sigchld._stime
@@ -221,6 +225,7 @@#define SIGEV_SIGNAL 0/* notify via signal */ #define SIGEV_NONE 1/* other notification: meaningless */ #define SIGEV_THREAD 2/* deliver via thread creation */ +#define SIGEV_THREAD_ID 4/* deliver to thread */ #define SIGEV_MAX_SIZE 64#ifndef SIGEV_PAD_SIZE
@@ -235,6 +240,7 @@int sigev_notify;union {int _pad[SIGEV_PAD_SIZE ]; +int _tid;struct {void (*_function)(sigval_t );
@@ -247,10 +253,12 @@#define sigev_notify_function _sigev_un._sigev_thread._function#define sigev_notify_attributes _sigev_un._sigev_thread._attribute +#define sigev_notify_thread_id _sigev_un._tid#ifdef __KERNEL__struct siginfo ; +void do_schedule_next_timer (struct siginfo *info);#ifndef HAVE_ARCH_COPY_SIGINFO
include/asm-i386/posix_types.h +2 -0
@@ -22,6 +22,8 @@typedef long __kernel_time_t ;typedef long __kernel_suseconds_t ;typedef long __kernel_clock_t ; +typedef int __kernel_timer_t ; +typedef int __kernel_clockid_t ;typedef int __kernel_daddr_t ;typedef char *__kernel_caddr_t ;typedef unsigned short __kernel_uid16_t ;
include/asm-i386/signal.h +76 -0
91 lines not on this page · raw message
include/asm-i386/unistd.h +9 -0
@@ -263,6 +263,15 @@#define __NR_sys_epoll_wait 256#define __NR_remap_file_pages 257#define __NR_set_tid_address 258 +#define __NR_timer_create 259 +#define __NR_timer_settime (__NR_timer_create+1) +#define __NR_timer_gettime (__NR_timer_create+2) +#define __NR_timer_getoverrun (__NR_timer_create+3) +#define __NR_timer_delete (__NR_timer_create+4) +#define __NR_clock_settime (__NR_timer_create+5) +#define __NR_clock_gettime (__NR_timer_create+6) +#define __NR_clock_getres (__NR_timer_create+7) +#define __NR_clock_nanosleep (__NR_timer_create+8)/* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
include/linux/id_reuse.h +119 -0
119 lines not on this page · raw message
include/linux/init_task.h +1 -0
@@ -93,6 +93,7 @@ .sig = &init_signals, \ .pending = { NULL, &tsk.pending.head, {{0}}}, \ .blocked = {{0}}, \ + .posix_timers = LIST_HEAD_INIT(tsk.posix_timers), \ .alloc_lock = SPIN_LOCK_UNLOCKED, \ .switch_lock = SPIN_LOCK_UNLOCKED, \ .journal_info = NULL, \
include/linux/posix-timers.h +29 -0
@@ -0,0 +1,29 @@ +#ifndef _linux_POSIX_TIMERS_H +#define _linux_POSIX_TIMERS_H + +struct k_clock { +int res;/* in nano seconds */ +int ( *clock_set)(struct timespec *tp); +int ( *clock_get)(struct timespec *tp); +int ( *nsleep)(int flags, +struct timespec *new_setting, +struct itimerspec *old_setting); +int ( *timer_set)(struct k_itimer *timr,int flags, +struct itimerspec *new_setting, +struct itimerspec *old_setting); +int ( *timer_del)(struct k_itimer *timr); +void ( *timer_get)(struct k_itimer *timr, +struct itimerspec *cur_setting); +}; +struct now_struct { +unsigned long jiffies; +}; +#define posix_get_now (now) (now)->jiffies = jiffies; +#define posix_time_before (timer, now) \ + time_before((timer)->expires, (now)->jiffies) + +#define posix_bump_timer (timr) do { \ + (timr)->it_timer.expires += (timr)->it_incr; \ + (timr)->it_overrun++; \ + }while (0) +#endif
include/linux/sched.h +21 -0
@@ -277,6 +277,25 @@typedef struct prio_array prio_array_t ;struct backing_dev_info ; +/* POSIX.1b interval timer structure. */ +struct k_itimer { +struct list_head list;/* free/ allocate list */ +spinlock_t it_lock; +clockid_t it_clock;/* which timer type */ +timer_t it_id;/* timer id */ +int it_overrun;/* overrun on pending signal */ +int it_overrun_last;/* overrun on last delivered signal */ +int it_requeue_pending;/* waiting to requeue this timer */ +int it_sigev_notify;/* notify word of sigevent struct */ +int it_sigev_signo;/* signo word of sigevent struct */ +sigval_t it_sigev_value;/* value word of sigevent struct */ +unsigned long it_incr;/* interval specified in jiffies */ +struct task_struct *it_process;/* process to send signal to */ +struct timer_list it_timer; +}; + + +struct task_struct {volatile long state;/* -1 unrunnable, 0 runnable, >0 stopped */ struct thread_info *thread_info;
@@ -340,6 +359,7 @@unsigned long it_real_value, it_prof_value, it_virt_value;unsigned long it_real_incr, it_prof_incr, it_virt_incr;struct timer_list real_timer; +struct list_head posix_timers;/* POSIX.1b Interval Timers */ unsigned long utime, stime, cutime, cstime;unsigned long start_time;long per_cpu_utime[NR_CPUS ], per_cpu_stime[NR_CPUS ];
@@ -581,6 +601,7 @@extern void exit_files (struct task_struct *);extern void exit_sighand (struct task_struct *);extern void __exit_sighand (struct task_struct *); +extern void exit_itimers (struct task_struct *);extern void reparent_to_init (void );extern void daemonize (void );
include/linux/signal.h +30 -0
@@ -224,6 +224,36 @@struct pt_regs ;extern int get_signal_to_deliver (siginfo_t *info,struct pt_regs *regs);#endif +/* +* We would like the asm/signal.h code to define these so that the using +* function can call do_signal(). In loo of that, we define a genaric +* version that pretends that do_signal() was called and delivered a signal. +* To see how this is used, see nano_sleep() in timer.c and the i386 version +* in asm_i386/signal.h. +*/ +#ifndef PT_REGS_ENTRY +#define PT_REGS_ENTRY (type,name,p1_type,p1, p2_type,p2) \ +type name(p1_type p1,p2_type p2)\ +{ +#endif +#ifndef _do_signal +#define _do_signal () 1 +#endif +#ifndef NANOSLEEP_ENTRY +#define NANOSLEEP_ENTRY (a) asmlinkage long sys_nanosleep( struct timespec* rqtp, \ + struct timespec * rmtp) \ +{ a +#endif +#ifndef CLOCK_NANOSLEEP_ENTRY +#define CLOCK_NANOSLEEP_ENTRY (a) asmlinkage long sys_clock_nanosleep( \ + clockid_t which_clock, \ + int flags, \ + const struct timespec *rqtp, \ + struct timespec *rmtp) \ +{ a + +#endif +#endif /* __KERNEL__ */
include/linux/sys.h +1 -2
@@ -2,9 +2,8 @@#define _LINUX_SYS_H/* -* system call entry points ... but not all are defined +* This file is no longer used or needed */ -#define NR_syscalls 260/* * These are system calls that will be removed at some time
include/linux/time.h +35 -0
@@ -40,6 +40,19 @@*/ #define MAX_JIFFY_OFFSET ((~0UL >> 1)-1) +/* Parameters used to convert the timespec values */ +#ifndef USEC_PER_SEC +#define USEC_PER_SEC (1000000L) +#endif + +#ifndef NSEC_PER_SEC +#define NSEC_PER_SEC (1000000000L) +#endif + +#ifndef NSEC_PER_USEC +#define NSEC_PER_USEC (1000L) +#endif +static __inline__unsigned long timespec_to_jiffies (struct timespec *value) {
@@ -138,6 +151,8 @@#ifdef __KERNEL__extern void do_gettimeofday (struct timeval *tv);extern void do_settimeofday (struct timeval *tv); +extern int do_sys_settimeofday (struct timeval *tv,struct timezone *tz); +extern void clock_was_set (void );// call when ever the clock is set #endif #define FD_SETSIZE __FD_SETSIZE
@@ -163,5 +178,25 @@struct timeval it_interval;/* timer interval */ struct timeval it_value; /* current value */ }; + + +/* +* The IDs of the various system clocks (for POSIX.1b interval timers). +*/ +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 +#define CLOCK_PROCESS_CPUTIME_ID 2 +#define CLOCK_THREAD_CPUTIME_ID 3 +#define CLOCK_REALTIME_HR 4 +#define CLOCK_MONOTONIC_HR 5 + +#define MAX_CLOCKS 6 + +/* +* The various flags for setting POSIX.1b interval timers. +*/ + +#define TIMER_ABSTIME 0x01 +#endif
include/linux/types.h +2 -0
@@ -23,6 +23,8 @@typedef __kernel_daddr_t daddr_t ;typedef __kernel_key_t key_t ;typedef __kernel_suseconds_t suseconds_t ; +typedef __kernel_timer_t timer_t ; +typedef __kernel_clockid_t clockid_t ;#ifdef __KERNEL__typedef __kernel_uid32_t uid_t ;
kernel/Makefile +1 -1
@@ -10,7 +10,7 @@ exit.o itimer.o time.o softirq.o resource.o \ sysctl.o capability.o ptrace.o timer.o user.o \ signal.o sys.o kmod.o workqueue.o futex.o platform.o pid.o \ - rcupdate.o intermodule.o extable.o + rcupdate.o intermodule.o extable.o posix-timers.o id_reuse.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o obj-$(CONFIG_SMP) += cpu.o
kernel/exit.c +2 -0
@@ -411,6 +411,7 @@mmdrop (active_mm); } +/* * Turn us into a lazy TLB process if we * aren't already..
@@ -660,6 +661,7 @@__exit_files (tsk);__exit_fs (tsk);exit_namespace (tsk); +exit_itimers (tsk);exit_thread ();if (current->leader)
kernel/fork.c +1 -0
@@ -822,6 +822,7 @@ goto bad_fork_cleanup_files;if (copy_sighand (clone_flags, p)) goto bad_fork_cleanup_fs; +INIT_LIST_HEAD (&p->posix_timers);if (copy_mm (clone_flags, p)) goto bad_fork_cleanup_sighand;if (copy_namespace (clone_flags, p))
kernel/id_reuse.c +198 -0
198 lines not on this page · raw message
kernel/posix-timers.c +1238 -0
1,238 lines not on this page · raw message
kernel/signal.c +31 -9
@@ -456,8 +456,6 @@if (!collect_signal (sig, pending, info)) sig =0 ; -/* XXX: Once POSIX.1b timers are in, if si_code == SI_TIMER, -we need to xchg out the timer overrun values. */ }recalc_sigpending ();
@@ -472,6 +470,7 @@*/ int dequeue_signal (sigset_t *mask,siginfo_t *info) { +int ret;/* * Here we handle shared pending signals. To implement the full * semantics we need to unqueue and resend them. It will likely
@@ -482,7 +481,13 @@if (signr)__send_sig_info (signr, info, current); } -return __dequeue_signal (¤t->pending, mask, info); + ret =__dequeue_signal (¤t->pending, mask, info); +if ( ret && + ((info->si_code & __SI_MASK) == __SI_TIMER) && + info->si_sys_private){ +do_schedule_next_timer (info); + } +return ret; }static int rm_from_queue (int sig,struct sigpending *s)
@@ -621,6 +626,7 @@static int send_signal (int sig,struct siginfo *info,struct sigpending *signals) {struct sigqueue * q =NULL ; +int ret =0 ;/* * fast-pathed signals for kernel-internal things like SIGSTOP
@@ -664,17 +670,26 @@copy_siginfo (&q->info, info);break ; } - }else if (sig >=SIGRTMIN && info && (unsigned long )info !=1 + }else { +if (sig >=SIGRTMIN && info && (unsigned long )info !=1 && info->si_code !=SI_USER )/* * Queue overflow, abort. We may abort if the signal was rt * and sent by user using something other than kill(). */ -return -EAGAIN ; +return -EAGAIN ; + +if (((unsigned long )info >1 ) && (info->si_code ==SI_TIMER )) +/* +* Set up a return to indicate that we dropped +* the signal. +*/ + ret = info->si_sys_private; + } out_set:sigaddset (&signals->signal, sig); -return 0 ; +return ret; }/*
@@ -714,7 +729,7 @@ {int retval =send_signal (sig, info, &t->pending); -if (!retval && !sigismember (&t->blocked, sig)) +if ((retval >=0 ) && !sigismember (&t->blocked, sig))signal_wake_up (t);return retval;
@@ -750,6 +765,12 @@handle_stop_signal (sig, t); +if (((unsigned long )info >2 ) && (info->si_code ==SI_TIMER )) +/* +* Set up a return to indicate that we dropped the signal. +*/ + ret = info->si_sys_private; +/* Optimize away the signal, if it's a signal that can be handled immediately (ie non-blocked and untraced) and that is ignored (either explicitly or by default). */
@@ -1464,8 +1485,9 @@ err |=__put_user (from->si_uid, &to->si_uid);break ;case __SI_TIMER: - err |=__put_user (from->si_timer1, &to->si_timer1); - err |=__put_user (from->si_timer2, &to->si_timer2); + err |=__put_user (from->si_tid, &to->si_tid); + err |=__put_user (from->si_overrun, &to->si_overrun); + err |=__put_user (from->si_ptr, &to->si_ptr);break ;case __SI_POLL: err |=__put_user (from->si_band, &to->si_band);
kernel/timer.c +41 -17
154 lines not on this page · raw message