/* Copyright (C) 1995, 1996 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. The GNU Hurd 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, or (at your option) any later version. The GNU Hurd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include #include #include #include #include "pfinet.h" long long root_jiffies; volatile struct mapped_time_value *mapped_time; struct timer_list *timers; thread_t timer_thread = 0; static int timer_function (int this_is_a_pointless_variable_with_a_rather_long_name) { mach_port_t recv; int wait = 0; recv = mach_reply_port (); timer_thread = mach_thread_self (); mutex_lock (&global_lock); while (1) { int jiff = jiffies; if (!timers) wait = -1; else if (timers->expires < jiff) wait = 0; else wait = ((timers->expires - jiff) * 1000) / HZ; mutex_unlock (&global_lock); mach_msg (NULL, (MACH_RCV_MSG | MACH_RCV_INTERRUPT | (wait == -1 ? 0 : MACH_RCV_TIMEOUT)), 0, 0, recv, wait, MACH_PORT_NULL); mutex_lock (&global_lock); while (timers->expires < jiffies) { struct timer_list *tp; tp = timers; timers = timers->next; if (timers) timers->prevp = &timers; tp->next = 0; tp->prevp = 0; (*tp->function) (tp->data); } } } void add_timer (struct timer_list *timer) { struct timer_list **tp; timer->expires += jiffies; for (tp = &timers; *tp; tp = &(*tp)->next) if ((*tp)->expires > timer->expires) { timer->next = *tp; timer->next->prevp = &timer->next; timer->prevp = tp; *tp = timer; break; } if (!*tp) { timer->next = 0; timer->prevp = tp; *tp = timer; } if (timers == timer) { /* We have change the first one, so tweak the timer thread to push things up. */ while (timer_thread == 0) swtch_pri (0); if (timer_thread != mach_thread_self ()) { thread_suspend (timer_thread); thread_abort (timer_thread); thread_resume (timer_thread); } } } int del_timer (struct timer_list *timer) { if (timer->prevp) { *timer->prevp = timer->next; if (timer->next) timer->next->prevp = timer->prevp; timer->next = 0; timer->prevp = 0; return 1; } else return 0; } void init_timer (struct timer_list *timer) { bzero (timer, sizeof (struct timer_list)); } void init_time () { device_t timedev; memory_object_t timeobj; struct timeval tp; device_open (master_device, 0, "time", &timedev); device_map (timedev, VM_PROT_READ, 0, sizeof (mapped_time_value_t), &timeobj, 0); vm_map (mach_task_self (), (vm_address_t *)&mapped_time, sizeof (mapped_time_value_t), 0, 1, timeobj, 0, 0, VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE); mach_port_deallocate (mach_task_self (), timedev); mach_port_deallocate (mach_task_self (), timeobj); fill_timeval (&tp); root_jiffies = (long long) tp.tv_sec * HZ + ((long long) tp.tv_usec * HZ) / 1000000; cthread_detach (cthread_fork ((cthread_fn_t) timer_function, 0)); }