diff options
Diffstat (limited to 'kernel/time/alarmtimer.c')
-rw-r--r-- | kernel/time/alarmtimer.c | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 48c2ee949e61..4058ad79d55f 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c | |||
@@ -215,6 +215,21 @@ static int alarmtimer_suspend(struct device *dev) | |||
215 | } | 215 | } |
216 | 216 | ||
217 | 217 | ||
218 | static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type) | ||
219 | { | ||
220 | ktime_t delta; | ||
221 | unsigned long flags; | ||
222 | struct alarm_base *base = &alarm_bases[type]; | ||
223 | |||
224 | delta = ktime_sub(absexp, base->gettime()); | ||
225 | |||
226 | spin_lock_irqsave(&freezer_delta_lock, flags); | ||
227 | if (!freezer_delta.tv64 || (delta.tv64 < freezer_delta.tv64)) | ||
228 | freezer_delta = delta; | ||
229 | spin_unlock_irqrestore(&freezer_delta_lock, flags); | ||
230 | } | ||
231 | |||
232 | |||
218 | /************************************************************************** | 233 | /************************************************************************** |
219 | * alarm kernel interface code | 234 | * alarm kernel interface code |
220 | */ | 235 | */ |
@@ -279,6 +294,309 @@ void alarm_cancel(struct alarm *alarm) | |||
279 | } | 294 | } |
280 | 295 | ||
281 | 296 | ||
297 | /************************************************************************** | ||
298 | * alarm posix interface code | ||
299 | */ | ||
300 | |||
301 | /* | ||
302 | * clock2alarm - helper that converts from clockid to alarmtypes | ||
303 | * @clockid: clockid. | ||
304 | * | ||
305 | * Helper function that converts from clockids to alarmtypes | ||
306 | */ | ||
307 | static enum alarmtimer_type clock2alarm(clockid_t clockid) | ||
308 | { | ||
309 | if (clockid == CLOCK_REALTIME_ALARM) | ||
310 | return ALARM_REALTIME; | ||
311 | if (clockid == CLOCK_BOOTTIME_ALARM) | ||
312 | return ALARM_BOOTTIME; | ||
313 | return -1; | ||
314 | } | ||
315 | |||
316 | /* | ||
317 | * alarm_handle_timer - Callback for posix timers | ||
318 | * @alarm: alarm that fired | ||
319 | * | ||
320 | * Posix timer callback for expired alarm timers. | ||
321 | */ | ||
322 | static void alarm_handle_timer(struct alarm *alarm) | ||
323 | { | ||
324 | struct k_itimer *ptr = container_of(alarm, struct k_itimer, | ||
325 | it.alarmtimer); | ||
326 | if (posix_timer_event(ptr, 0) != 0) | ||
327 | ptr->it_overrun++; | ||
328 | } | ||
329 | |||
330 | /* | ||
331 | * alarm_clock_getres - posix getres interface | ||
332 | * @which_clock: clockid | ||
333 | * @tp: timespec to fill | ||
334 | * | ||
335 | * Returns the granularity of underlying alarm base clock | ||
336 | */ | ||
337 | static int alarm_clock_getres(const clockid_t which_clock, struct timespec *tp) | ||
338 | { | ||
339 | clockid_t baseid = alarm_bases[clock2alarm(which_clock)].base_clockid; | ||
340 | |||
341 | return hrtimer_get_res(baseid, tp); | ||
342 | } | ||
343 | |||
344 | /** | ||
345 | * alarm_clock_get - posix clock_get interface | ||
346 | * @which_clock: clockid | ||
347 | * @tp: timespec to fill. | ||
348 | * | ||
349 | * Provides the underlying alarm base time. | ||
350 | */ | ||
351 | static int alarm_clock_get(clockid_t which_clock, struct timespec *tp) | ||
352 | { | ||
353 | struct alarm_base *base = &alarm_bases[clock2alarm(which_clock)]; | ||
354 | |||
355 | *tp = ktime_to_timespec(base->gettime()); | ||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | /** | ||
360 | * alarm_timer_create - posix timer_create interface | ||
361 | * @new_timer: k_itimer pointer to manage | ||
362 | * | ||
363 | * Initializes the k_itimer structure. | ||
364 | */ | ||
365 | static int alarm_timer_create(struct k_itimer *new_timer) | ||
366 | { | ||
367 | enum alarmtimer_type type; | ||
368 | struct alarm_base *base; | ||
369 | |||
370 | if (!capable(CAP_WAKE_ALARM)) | ||
371 | return -EPERM; | ||
372 | |||
373 | type = clock2alarm(new_timer->it_clock); | ||
374 | base = &alarm_bases[type]; | ||
375 | alarm_init(&new_timer->it.alarmtimer, type, alarm_handle_timer); | ||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | /** | ||
380 | * alarm_timer_get - posix timer_get interface | ||
381 | * @new_timer: k_itimer pointer | ||
382 | * @cur_setting: itimerspec data to fill | ||
383 | * | ||
384 | * Copies the itimerspec data out from the k_itimer | ||
385 | */ | ||
386 | static void alarm_timer_get(struct k_itimer *timr, | ||
387 | struct itimerspec *cur_setting) | ||
388 | { | ||
389 | cur_setting->it_interval = | ||
390 | ktime_to_timespec(timr->it.alarmtimer.period); | ||
391 | cur_setting->it_value = | ||
392 | ktime_to_timespec(timr->it.alarmtimer.node.expires); | ||
393 | return; | ||
394 | } | ||
395 | |||
396 | /** | ||
397 | * alarm_timer_del - posix timer_del interface | ||
398 | * @timr: k_itimer pointer to be deleted | ||
399 | * | ||
400 | * Cancels any programmed alarms for the given timer. | ||
401 | */ | ||
402 | static int alarm_timer_del(struct k_itimer *timr) | ||
403 | { | ||
404 | alarm_cancel(&timr->it.alarmtimer); | ||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | /** | ||
409 | * alarm_timer_set - posix timer_set interface | ||
410 | * @timr: k_itimer pointer to be deleted | ||
411 | * @flags: timer flags | ||
412 | * @new_setting: itimerspec to be used | ||
413 | * @old_setting: itimerspec being replaced | ||
414 | * | ||
415 | * Sets the timer to new_setting, and starts the timer. | ||
416 | */ | ||
417 | static int alarm_timer_set(struct k_itimer *timr, int flags, | ||
418 | struct itimerspec *new_setting, | ||
419 | struct itimerspec *old_setting) | ||
420 | { | ||
421 | /* Save old values */ | ||
422 | old_setting->it_interval = | ||
423 | ktime_to_timespec(timr->it.alarmtimer.period); | ||
424 | old_setting->it_value = | ||
425 | ktime_to_timespec(timr->it.alarmtimer.node.expires); | ||
426 | |||
427 | /* If the timer was already set, cancel it */ | ||
428 | alarm_cancel(&timr->it.alarmtimer); | ||
429 | |||
430 | /* start the timer */ | ||
431 | alarm_start(&timr->it.alarmtimer, | ||
432 | timespec_to_ktime(new_setting->it_value), | ||
433 | timespec_to_ktime(new_setting->it_interval)); | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | /** | ||
438 | * alarmtimer_nsleep_wakeup - Wakeup function for alarm_timer_nsleep | ||
439 | * @alarm: ptr to alarm that fired | ||
440 | * | ||
441 | * Wakes up the task that set the alarmtimer | ||
442 | */ | ||
443 | static void alarmtimer_nsleep_wakeup(struct alarm *alarm) | ||
444 | { | ||
445 | struct task_struct *task = (struct task_struct *)alarm->data; | ||
446 | |||
447 | alarm->data = NULL; | ||
448 | if (task) | ||
449 | wake_up_process(task); | ||
450 | } | ||
451 | |||
452 | /** | ||
453 | * alarmtimer_do_nsleep - Internal alarmtimer nsleep implementation | ||
454 | * @alarm: ptr to alarmtimer | ||
455 | * @absexp: absolute expiration time | ||
456 | * | ||
457 | * Sets the alarm timer and sleeps until it is fired or interrupted. | ||
458 | */ | ||
459 | static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp) | ||
460 | { | ||
461 | alarm->data = (void *)current; | ||
462 | do { | ||
463 | set_current_state(TASK_INTERRUPTIBLE); | ||
464 | alarm_start(alarm, absexp, ktime_set(0, 0)); | ||
465 | if (likely(alarm->data)) | ||
466 | schedule(); | ||
467 | |||
468 | alarm_cancel(alarm); | ||
469 | } while (alarm->data && !signal_pending(current)); | ||
470 | |||
471 | __set_current_state(TASK_RUNNING); | ||
472 | |||
473 | return (alarm->data == NULL); | ||
474 | } | ||
475 | |||
476 | |||
477 | /** | ||
478 | * update_rmtp - Update remaining timespec value | ||
479 | * @exp: expiration time | ||
480 | * @type: timer type | ||
481 | * @rmtp: user pointer to remaining timepsec value | ||
482 | * | ||
483 | * Helper function that fills in rmtp value with time between | ||
484 | * now and the exp value | ||
485 | */ | ||
486 | static int update_rmtp(ktime_t exp, enum alarmtimer_type type, | ||
487 | struct timespec __user *rmtp) | ||
488 | { | ||
489 | struct timespec rmt; | ||
490 | ktime_t rem; | ||
491 | |||
492 | rem = ktime_sub(exp, alarm_bases[type].gettime()); | ||
493 | |||
494 | if (rem.tv64 <= 0) | ||
495 | return 0; | ||
496 | rmt = ktime_to_timespec(rem); | ||
497 | |||
498 | if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) | ||
499 | return -EFAULT; | ||
500 | |||
501 | return 1; | ||
502 | |||
503 | } | ||
504 | |||
505 | /** | ||
506 | * alarm_timer_nsleep_restart - restartblock alarmtimer nsleep | ||
507 | * @restart: ptr to restart block | ||
508 | * | ||
509 | * Handles restarted clock_nanosleep calls | ||
510 | */ | ||
511 | static long __sched alarm_timer_nsleep_restart(struct restart_block *restart) | ||
512 | { | ||
513 | enum alarmtimer_type type = restart->nanosleep.index; | ||
514 | ktime_t exp; | ||
515 | struct timespec __user *rmtp; | ||
516 | struct alarm alarm; | ||
517 | int ret = 0; | ||
518 | |||
519 | exp.tv64 = restart->nanosleep.expires; | ||
520 | alarm_init(&alarm, type, alarmtimer_nsleep_wakeup); | ||
521 | |||
522 | if (alarmtimer_do_nsleep(&alarm, exp)) | ||
523 | goto out; | ||
524 | |||
525 | if (freezing(current)) | ||
526 | alarmtimer_freezerset(exp, type); | ||
527 | |||
528 | rmtp = restart->nanosleep.rmtp; | ||
529 | if (rmtp) { | ||
530 | ret = update_rmtp(exp, type, rmtp); | ||
531 | if (ret <= 0) | ||
532 | goto out; | ||
533 | } | ||
534 | |||
535 | |||
536 | /* The other values in restart are already filled in */ | ||
537 | ret = -ERESTART_RESTARTBLOCK; | ||
538 | out: | ||
539 | return ret; | ||
540 | } | ||
541 | |||
542 | /** | ||
543 | * alarm_timer_nsleep - alarmtimer nanosleep | ||
544 | * @which_clock: clockid | ||
545 | * @flags: determins abstime or relative | ||
546 | * @tsreq: requested sleep time (abs or rel) | ||
547 | * @rmtp: remaining sleep time saved | ||
548 | * | ||
549 | * Handles clock_nanosleep calls against _ALARM clockids | ||
550 | */ | ||
551 | static int alarm_timer_nsleep(const clockid_t which_clock, int flags, | ||
552 | struct timespec *tsreq, struct timespec __user *rmtp) | ||
553 | { | ||
554 | enum alarmtimer_type type = clock2alarm(which_clock); | ||
555 | struct alarm alarm; | ||
556 | ktime_t exp; | ||
557 | int ret = 0; | ||
558 | struct restart_block *restart; | ||
559 | |||
560 | if (!capable(CAP_WAKE_ALARM)) | ||
561 | return -EPERM; | ||
562 | |||
563 | alarm_init(&alarm, type, alarmtimer_nsleep_wakeup); | ||
564 | |||
565 | exp = timespec_to_ktime(*tsreq); | ||
566 | /* Convert (if necessary) to absolute time */ | ||
567 | if (flags != TIMER_ABSTIME) { | ||
568 | ktime_t now = alarm_bases[type].gettime(); | ||
569 | exp = ktime_add(now, exp); | ||
570 | } | ||
571 | |||
572 | if (alarmtimer_do_nsleep(&alarm, exp)) | ||
573 | goto out; | ||
574 | |||
575 | if (freezing(current)) | ||
576 | alarmtimer_freezerset(exp, type); | ||
577 | |||
578 | /* abs timers don't set remaining time or restart */ | ||
579 | if (flags == TIMER_ABSTIME) { | ||
580 | ret = -ERESTARTNOHAND; | ||
581 | goto out; | ||
582 | } | ||
583 | |||
584 | if (rmtp) { | ||
585 | ret = update_rmtp(exp, type, rmtp); | ||
586 | if (ret <= 0) | ||
587 | goto out; | ||
588 | } | ||
589 | |||
590 | restart = ¤t_thread_info()->restart_block; | ||
591 | restart->fn = alarm_timer_nsleep_restart; | ||
592 | restart->nanosleep.index = type; | ||
593 | restart->nanosleep.expires = exp.tv64; | ||
594 | restart->nanosleep.rmtp = rmtp; | ||
595 | ret = -ERESTART_RESTARTBLOCK; | ||
596 | |||
597 | out: | ||
598 | return ret; | ||
599 | } | ||
282 | 600 | ||
283 | /************************************************************************** | 601 | /************************************************************************** |
284 | * alarmtimer initialization code | 602 | * alarmtimer initialization code |
@@ -306,6 +624,18 @@ static int __init alarmtimer_init(void) | |||
306 | { | 624 | { |
307 | int error = 0; | 625 | int error = 0; |
308 | int i; | 626 | int i; |
627 | struct k_clock alarm_clock = { | ||
628 | .clock_getres = alarm_clock_getres, | ||
629 | .clock_get = alarm_clock_get, | ||
630 | .timer_create = alarm_timer_create, | ||
631 | .timer_set = alarm_timer_set, | ||
632 | .timer_del = alarm_timer_del, | ||
633 | .timer_get = alarm_timer_get, | ||
634 | .nsleep = alarm_timer_nsleep, | ||
635 | }; | ||
636 | |||
637 | posix_timers_register_clock(CLOCK_REALTIME_ALARM, &alarm_clock); | ||
638 | posix_timers_register_clock(CLOCK_BOOTTIME_ALARM, &alarm_clock); | ||
309 | 639 | ||
310 | /* Initialize alarm bases */ | 640 | /* Initialize alarm bases */ |
311 | alarm_bases[ALARM_REALTIME].base_clockid = CLOCK_REALTIME; | 641 | alarm_bases[ALARM_REALTIME].base_clockid = CLOCK_REALTIME; |