]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/posix-timers.c
clocksource: introduce CLOCK_MONOTONIC_RAW
[linux-2.6-omap-h63xx.git] / kernel / posix-timers.c
index dbd8398ddb0b41fa1f391849b82199078e72de70..d3c66b53dff67fd93bcd562f95c7e515ea99816b 100644 (file)
@@ -222,6 +222,15 @@ static int posix_ktime_get_ts(clockid_t which_clock, struct timespec *tp)
        return 0;
 }
 
+/*
+ * Get monotonic time for posix timers
+ */
+static int posix_get_monotonic_raw(clockid_t which_clock, struct timespec *tp)
+{
+       getrawmonotonic(tp);
+       return 0;
+}
+
 /*
  * Initialize everything, well, just everything in Posix clocks/timers ;)
  */
@@ -235,9 +244,15 @@ static __init int init_posix_timers(void)
                .clock_get = posix_ktime_get_ts,
                .clock_set = do_posix_clock_nosettime,
        };
+       struct k_clock clock_monotonic_raw = {
+               .clock_getres = hrtimer_get_res,
+               .clock_get = posix_get_monotonic_raw,
+               .clock_set = do_posix_clock_nosettime,
+       };
 
        register_posix_clock(CLOCK_REALTIME, &clock_realtime);
        register_posix_clock(CLOCK_MONOTONIC, &clock_monotonic);
+       register_posix_clock(CLOCK_MONOTONIC_RAW, &clock_monotonic_raw);
 
        posix_timers_cache = kmem_cache_create("posix_timers_cache",
                                        sizeof (struct k_itimer), 0, SLAB_PANIC,
@@ -289,21 +304,29 @@ void do_schedule_next_timer(struct siginfo *info)
                else
                        schedule_next_timer(timr);
 
-               info->si_overrun = timr->it_overrun_last;
+               info->si_overrun += timr->it_overrun_last;
        }
 
        if (timr)
                unlock_timer(timr, flags);
 }
 
-int posix_timer_event(struct k_itimer *timr,int si_private)
+int posix_timer_event(struct k_itimer *timr, int si_private)
 {
-       memset(&timr->sigq->info, 0, sizeof(siginfo_t));
+       /*
+        * FIXME: if ->sigq is queued we can race with
+        * dequeue_signal()->do_schedule_next_timer().
+        *
+        * If dequeue_signal() sees the "right" value of
+        * si_sys_private it calls do_schedule_next_timer().
+        * We re-queue ->sigq and drop ->it_lock().
+        * do_schedule_next_timer() locks the timer
+        * and re-schedules it while ->sigq is pending.
+        * Not really bad, but not that we want.
+        */
        timr->sigq->info.si_sys_private = si_private;
-       /* Send signal to the process that owns this timer.*/
 
        timr->sigq->info.si_signo = timr->it_sigev_signo;
-       timr->sigq->info.si_errno = 0;
        timr->sigq->info.si_code = SI_TIMER;
        timr->sigq->info.si_tid = timr->it_id;
        timr->sigq->info.si_value = timr->it_sigev_value;
@@ -435,6 +458,7 @@ static struct k_itimer * alloc_posix_timer(void)
                kmem_cache_free(posix_timers_cache, tmr);
                tmr = NULL;
        }
+       memset(&tmr->sigq->info, 0, sizeof(siginfo_t));
        return tmr;
 }
 
@@ -449,9 +473,6 @@ static void release_posix_timer(struct k_itimer *tmr, int it_id_set)
                spin_unlock_irqrestore(&idr_lock, flags);
        }
        sigqueue_free(tmr->sigq);
-       if (unlikely(tmr->it_process) &&
-           tmr->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID))
-               put_task_struct(tmr->it_process);
        kmem_cache_free(posix_timers_cache, tmr);
 }
 
@@ -856,11 +877,10 @@ retry_delete:
         * This keeps any tasks waiting on the spin lock from thinking
         * they got something (see the lock code above).
         */
-       if (timer->it_process) {
-               if (timer->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID))
-                       put_task_struct(timer->it_process);
-               timer->it_process = NULL;
-       }
+       if (timer->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID))
+               put_task_struct(timer->it_process);
+       timer->it_process = NULL;
+
        unlock_timer(timer, flags);
        release_posix_timer(timer, IT_ID_SET);
        return 0;
@@ -885,11 +905,10 @@ retry_delete:
         * This keeps any tasks waiting on the spin lock from thinking
         * they got something (see the lock code above).
         */
-       if (timer->it_process) {
-               if (timer->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID))
-                       put_task_struct(timer->it_process);
-               timer->it_process = NULL;
-       }
+       if (timer->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID))
+               put_task_struct(timer->it_process);
+       timer->it_process = NULL;
+
        unlock_timer(timer, flags);
        release_posix_timer(timer, IT_ID_SET);
 }