]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/mk_timer.c
xnu-517.7.7.tar.gz
[apple/xnu.git] / osfmk / kern / mk_timer.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
e5568f75
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
1c79356b 11 *
e5568f75
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
e5568f75
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
24 *
25 * HISTORY
26 *
27 * 29 June 2000 (debo)
28 * Created.
29 */
30
31#include <mach/mach_types.h>
32#include <mach/mach_port_server.h>
33
34#include <mach/mk_timer.h>
35
36#include <ipc/ipc_space.h>
37
38#include <kern/mk_timer.h>
39#include <kern/thread_call.h>
40
41static zone_t mk_timer_zone;
42
43static mach_port_qos_t mk_timer_qos = {
44 FALSE, TRUE, 0, sizeof (mk_timer_expire_msg_t)
45};
46
47static void mk_timer_expire(
48 void *p0,
49 void *p1);
50
51mach_port_name_t
52mk_timer_create(void)
53{
54 mk_timer_t timer;
55 ipc_space_t myspace = current_space();
56 mach_port_name_t name = MACH_PORT_NULL;
57 ipc_port_t port;
58 kern_return_t result;
59
60 timer = (mk_timer_t)zalloc(mk_timer_zone);
61 if (timer == NULL)
62 return (MACH_PORT_NULL);
63
64 result = mach_port_allocate_qos(myspace, MACH_PORT_RIGHT_RECEIVE,
65 &mk_timer_qos, &name);
66 if (result == KERN_SUCCESS)
67 result = ipc_port_translate_receive(myspace, name, &port);
68
69 if (result != KERN_SUCCESS) {
70 zfree(mk_timer_zone, (vm_offset_t)timer);
71
72 return (MACH_PORT_NULL);
73 }
74
75 simple_lock_init(&timer->lock, ETAP_MISC_TIMER);
76 call_entry_setup(&timer->call_entry, mk_timer_expire, timer);
77 timer->is_armed = timer->is_dead = FALSE;
78 timer->active = 0;
79
80 timer->port = port;
81 ipc_kobject_set_atomically(port, (ipc_kobject_t)timer, IKOT_TIMER);
82
83 port->ip_srights++;
84 ip_reference(port);
85 ip_unlock(port);
86
87 return (name);
88}
89
90void
91mk_timer_port_destroy(
92 ipc_port_t port)
93{
94 mk_timer_t timer = NULL;
95
96 ip_lock(port);
97 if (ip_kotype(port) == IKOT_TIMER) {
98 timer = (mk_timer_t)port->ip_kobject;
99 assert(timer != NULL);
100 ipc_kobject_set_atomically(port, IKO_NULL, IKOT_NONE);
101 simple_lock(&timer->lock);
102 assert(timer->port == port);
103 }
104 ip_unlock(port);
105
106 if (timer != NULL) {
107 if (thread_call_cancel(&timer->call_entry))
108 timer->active--;
109 timer->is_armed = FALSE;
110
111 timer->is_dead = TRUE;
112 if (timer->active == 0) {
113 simple_unlock(&timer->lock);
114 zfree(mk_timer_zone, (vm_offset_t)timer);
115
116 ipc_port_release_send(port);
117 return;
118 }
119
120 simple_unlock(&timer->lock);
121 }
122}
123
124void
55e303ae 125mk_timer_init(void)
1c79356b
A
126{
127 int s = sizeof (mk_timer_data_t);
128
129 assert(!(mk_timer_zone != NULL));
130
131 mk_timer_zone = zinit(s, (4096 * s), (16 * s), "mk_timer");
132}
133
134static void
135mk_timer_expire(
136 void *p0,
137 void *p1)
138{
1c79356b
A
139 mk_timer_t timer = p0;
140 ipc_port_t port;
141
1c79356b
A
142 simple_lock(&timer->lock);
143
144 if (timer->active > 1) {
145 timer->active--;
146 simple_unlock(&timer->lock);
147 return;
148 }
149
150 port = timer->port;
151 assert(port != IP_NULL);
55e303ae 152 assert(timer->active == 1);
1c79356b 153
55e303ae 154 while (timer->is_armed && timer->active == 1) {
1c79356b
A
155 mk_timer_expire_msg_t msg;
156
157 timer->is_armed = FALSE;
1c79356b
A
158 simple_unlock(&timer->lock);
159
160 msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
161 msg.header.msgh_remote_port = port;
162 msg.header.msgh_local_port = MACH_PORT_NULL;
163 msg.header.msgh_reserved = msg.header.msgh_id = 0;
164
55e303ae
A
165 msg.unused[0] = msg.unused[1] = msg.unused[2] = 0;
166
1c79356b
A
167 (void) mach_msg_send_from_kernel(&msg.header, sizeof (msg));
168
169 simple_lock(&timer->lock);
170 }
171
172 if (--timer->active == 0 && timer->is_dead) {
173 simple_unlock(&timer->lock);
174 zfree(mk_timer_zone, (vm_offset_t)timer);
175
176 ipc_port_release_send(port);
177 return;
178 }
179
180 simple_unlock(&timer->lock);
181}
182
183kern_return_t
184mk_timer_destroy(
185 mach_port_name_t name)
186{
187 ipc_space_t myspace = current_space();
188 ipc_port_t port;
189 kern_return_t result;
190
191 result = ipc_port_translate_receive(myspace, name, &port);
192 if (result != KERN_SUCCESS)
193 return (result);
194
195 if (ip_kotype(port) == IKOT_TIMER) {
196 ip_unlock(port);
197 result = mach_port_destroy(myspace, name);
198 }
199 else {
200 ip_unlock(port);
201 result = KERN_INVALID_ARGUMENT;
202 }
203
204 return (result);
205}
206
207kern_return_t
208mk_timer_arm(
209 mach_port_name_t name,
0b4e3aa0 210 uint64_t expire_time)
1c79356b 211{
0b4e3aa0 212 uint64_t time_of_arming;
1c79356b
A
213 mk_timer_t timer;
214 ipc_space_t myspace = current_space();
215 ipc_port_t port;
216 kern_return_t result;
217
218 clock_get_uptime(&time_of_arming);
219
220 result = ipc_port_translate_receive(myspace, name, &port);
221 if (result != KERN_SUCCESS)
222 return (result);
223
224 if (ip_kotype(port) == IKOT_TIMER) {
225 timer = (mk_timer_t)port->ip_kobject;
226 assert(timer != NULL);
227 simple_lock(&timer->lock);
228 assert(timer->port == port);
229 ip_unlock(port);
230
55e303ae
A
231 if (!timer->is_dead) {
232 timer->time_of_arming = time_of_arming;
233 timer->is_armed = TRUE;
234
235 if (!thread_call_enter_delayed(&timer->call_entry, expire_time))
236 timer->active++;
237 }
1c79356b 238
1c79356b
A
239 simple_unlock(&timer->lock);
240 }
241 else {
242 ip_unlock(port);
243 result = KERN_INVALID_ARGUMENT;
244 }
245
246 return (result);
247}
248
249kern_return_t
250mk_timer_cancel(
251 mach_port_name_t name,
0b4e3aa0 252 uint64_t *result_time)
1c79356b 253{
0b4e3aa0 254 uint64_t armed_time = 0;
1c79356b
A
255 mk_timer_t timer;
256 ipc_space_t myspace = current_space();
257 ipc_port_t port;
258 kern_return_t result;
259
260 result = ipc_port_translate_receive(myspace, name, &port);
261 if (result != KERN_SUCCESS)
262 return (result);
263
264 if (ip_kotype(port) == IKOT_TIMER) {
265 timer = (mk_timer_t)port->ip_kobject;
266 assert(timer != NULL);
267 simple_lock(&timer->lock);
268 assert(timer->port == port);
269 ip_unlock(port);
270
271 if (timer->is_armed) {
272 armed_time = timer->call_entry.deadline;
273 if (thread_call_cancel(&timer->call_entry))
274 timer->active--;
275 timer->is_armed = FALSE;
276 }
277
278 simple_unlock(&timer->lock);
279 }
280 else {
281 ip_unlock(port);
282 result = KERN_INVALID_ARGUMENT;
283 }
284
285 if (result == KERN_SUCCESS)
286 if ( result_time != NULL &&
287 copyout((void *)&armed_time, (void *)result_time,
288 sizeof (armed_time)) != 0 )
289 result = KERN_FAILURE;
290
291 return (result);
292}