source: mainline/uspace/lib/c/generic/time.c@ 86d7bfa

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 86d7bfa was 6119f24, checked in by Martin Decky <martin@…>, 14 years ago

map klog area and clock page directly in tasks which require them (do not use the memory sharing from naming service via IPC)
this avoids the circular dependency between gettimeofday() and the async framework (as reported by Jakub Jermar)
it also simplifies the code of the naming service (the memory sharing was never strictly necessary, it was only a demonstrator)

  • Property mode set to 100644
File size: 5.2 KB
Line 
1/*
2 * Copyright (c) 2006 Ondrej Palkovsky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libc
30 * @{
31 */
32/** @file
33 */
34
35#include <sys/time.h>
36#include <time.h>
37#include <bool.h>
38#include <arch/barrier.h>
39#include <macros.h>
40#include <errno.h>
41#include <sysinfo.h>
42#include <as.h>
43#include <ddi.h>
44#include <libc.h>
45
46/** Pointer to kernel shared variables with time */
47struct {
48 volatile sysarg_t seconds1;
49 volatile sysarg_t useconds;
50 volatile sysarg_t seconds2;
51} *ktime = NULL;
52
53/** Add microseconds to given timeval.
54 *
55 * @param tv Destination timeval.
56 * @param usecs Number of microseconds to add.
57 *
58 */
59void tv_add(struct timeval *tv, suseconds_t usecs)
60{
61 tv->tv_sec += usecs / 1000000;
62 tv->tv_usec += usecs % 1000000;
63
64 if (tv->tv_usec > 1000000) {
65 tv->tv_sec++;
66 tv->tv_usec -= 1000000;
67 }
68}
69
70/** Subtract two timevals.
71 *
72 * @param tv1 First timeval.
73 * @param tv2 Second timeval.
74 *
75 * @return Difference between tv1 and tv2 (tv1 - tv2) in
76 * microseconds.
77 *
78 */
79suseconds_t tv_sub(struct timeval *tv1, struct timeval *tv2)
80{
81 return (tv1->tv_usec - tv2->tv_usec) +
82 ((tv1->tv_sec - tv2->tv_sec) * 1000000);
83}
84
85/** Decide if one timeval is greater than the other.
86 *
87 * @param t1 First timeval.
88 * @param t2 Second timeval.
89 *
90 * @return True if tv1 is greater than tv2.
91 * @return False otherwise.
92 *
93 */
94int tv_gt(struct timeval *tv1, struct timeval *tv2)
95{
96 if (tv1->tv_sec > tv2->tv_sec)
97 return true;
98
99 if ((tv1->tv_sec == tv2->tv_sec) && (tv1->tv_usec > tv2->tv_usec))
100 return true;
101
102 return false;
103}
104
105/** Decide if one timeval is greater than or equal to the other.
106 *
107 * @param tv1 First timeval.
108 * @param tv2 Second timeval.
109 *
110 * @return True if tv1 is greater than or equal to tv2.
111 * @return False otherwise.
112 *
113 */
114int tv_gteq(struct timeval *tv1, struct timeval *tv2)
115{
116 if (tv1->tv_sec > tv2->tv_sec)
117 return true;
118
119 if ((tv1->tv_sec == tv2->tv_sec) && (tv1->tv_usec >= tv2->tv_usec))
120 return true;
121
122 return false;
123}
124
125/** Get time of day
126 *
127 * The time variables are memory mapped (read-only) from kernel which
128 * updates them periodically.
129 *
130 * As it is impossible to read 2 values atomically, we use a trick:
131 * First we read the seconds, then we read the microseconds, then we
132 * read the seconds again. If a second elapsed in the meantime, set
133 * the microseconds to zero.
134 *
135 * This assures that the values returned by two subsequent calls
136 * to gettimeofday() are monotonous.
137 *
138 */
139int gettimeofday(struct timeval *tv, struct timezone *tz)
140{
141 if (ktime == NULL) {
142 uintptr_t faddr;
143 int rc = sysinfo_get_value("clock.faddr", &faddr);
144 if (rc != EOK) {
145 errno = rc;
146 return -1;
147 }
148
149 void *addr = as_get_mappable_page(PAGE_SIZE);
150 if (addr == NULL) {
151 errno = ENOMEM;
152 return -1;
153 }
154
155 rc = physmem_map((void *) faddr, addr, 1,
156 AS_AREA_READ | AS_AREA_CACHEABLE);
157 if (rc != EOK) {
158 as_area_destroy(addr);
159 errno = rc;
160 return -1;
161 }
162
163 ktime = addr;
164 }
165
166 if (tz) {
167 tz->tz_minuteswest = 0;
168 tz->tz_dsttime = DST_NONE;
169 }
170
171 sysarg_t s2 = ktime->seconds2;
172
173 read_barrier();
174 tv->tv_usec = ktime->useconds;
175
176 read_barrier();
177 sysarg_t s1 = ktime->seconds1;
178
179 if (s1 != s2) {
180 tv->tv_sec = max(s1, s2);
181 tv->tv_usec = 0;
182 } else
183 tv->tv_sec = s1;
184
185 return 0;
186}
187
188time_t time(time_t *tloc)
189{
190 struct timeval tv;
191 if (gettimeofday(&tv, NULL))
192 return (time_t) -1;
193
194 if (tloc)
195 *tloc = tv.tv_sec;
196
197 return tv.tv_sec;
198}
199
200/** Wait unconditionally for specified number of microseconds
201 *
202 */
203int usleep(useconds_t usec)
204{
205 (void) __SYSCALL1(SYS_THREAD_USLEEP, usec);
206 return 0;
207}
208
209/** Wait unconditionally for specified number of seconds
210 *
211 */
212unsigned int sleep(unsigned int sec)
213{
214 /*
215 * Sleep in 1000 second steps to support
216 * full argument range
217 */
218
219 while (sec > 0) {
220 unsigned int period = (sec > 1000) ? 1000 : sec;
221
222 usleep(period * 1000000);
223 sec -= period;
224 }
225
226 return 0;
227}
228
229/** @}
230 */
Note: See TracBrowser for help on using the repository browser.