|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24: /* Copyright (c) 1991 NeXT Computer, Inc. All rights reserved.
25: *
26: * libIO.m - IO Library, user version.
27: *
28: * HISTORY
29: * 17-Apr-91 Doug Mitchell at NeXT
30: * Created.
31: */
32:
33: #import <bsd/sys/types.h>
34: #import <objc/objc.h>
35: #import <driverkit/return.h>
36: #import <driverkit/memcpy.h>
37: #import <driverkit/generalFuncs.h>
38: #import <mach/cthreads.h>
39: #import <mach/mach.h>
40: #import <bsd/syslog.h>
41: #import <stdarg.h>
42: #import <machkit/NXLock.h>
43: #import <kernserv/queue.h>
44: #import <driverkit/Device_ddm.h>
45: #import <kern/time_stamp.h>
46:
47: #if 0
48: /*
49: * For now...
50: */
51: #define xpr_libio(x,a,b,c,d,e) printf(x,a,b,c,d,e)
52: #endif 0
53:
54: /*
55: * Struct for queueing IOScheduleFunc() requests.
56: */
57: typedef struct {
58: IOThreadFunc fcn;
59: void *arg;
60: ns_time_t calloutTime;
61: queue_chain_t link;
62: } ioCallout_t;
63:
64: /*
65: * Static variables for this module.
66: */
67: static queue_head_t calloutChain; // queue of ioCallout_t's
68: static id calloutLock; // NXLock
69: static port_t sleepPort;
70:
71: /*
72: * Local prototypes.
73: */
74: static void calloutThread(void *foo);
75:
76: /*
77: * User-level libIO implementation.
78: */
79:
80: void *IOMalloc(int size)
81: {
82: return(malloc(size));
83: }
84:
85: void IOFree(void *p, int size)
86: {
87: free(p);
88: }
89:
90: void IOCopyMemory(void *from, void *to, unsigned int numBytes,
91: unsigned int bytesPerTransfer)
92: {
93: _IOCopyMemory(from, to, numBytes, bytesPerTransfer);
94: }
95:
96: /*
97: * Note in user space:
98: * IOThread == cthread_t
99: * IOThreadFunc = cthread_fn_t
100: * for now.
101: */
102: IOThread IOForkThread(IOThreadFunc fcn, void *arg)
103: {
104: return((IOThread)cthread_fork((cthread_fn_t)fcn, (any_t *)arg));
105: }
106:
107: void IOSuspendThread(IOThread thread)
108: {
109: cthread_t cth = (cthread_t)thread;
110:
111: /*
112: * Note no cthread_suspend...what a kludge.
113: */
114: thread_suspend(cthread_thread(cth));
115: }
116:
117: void IOResumeThread(IOThread thread)
118: {
119: cthread_t cth = (cthread_t)thread;
120:
121: thread_resume(cthread_thread(cth));
122: }
123:
124: /*
125: * 30-Jul-91 - removed IOThreadAbort(); there's no way for this to work
126: * cleanly (dmitch)
127: */
128: #ifdef notdef
129: void IOThreadAbort(IOThread thread)
130: {
131: cthread_abort(thread);
132: }
133: #endif notdef
134:
135: volatile void IOExitThread()
136: {
137: (volatile void)cthread_exit((any_t)-1);
138: }
139:
140: /*
141: * Sleep for indicated number of milliseconds.
142: *
143: * Current implementation is like libc's msleep, which uses
144: * the millisecond-resolution timeout on a msg_receive() on a local
145: * port (to which no messages will ever be sent). Unlike the libc version,
146: * this will return if the current thread is interrupted before the desired
147: * delay expires.
148: */
149: void IOSleep(unsigned milliseconds)
150: {
151: msg_header_t null_msg;
152:
153: null_msg.msg_local_port = sleepPort;
154: null_msg.msg_size = sizeof(null_msg);
155: msg_receive(&null_msg, RCV_TIMEOUT|RCV_INTERRUPT, milliseconds);
156: }
157:
158: /*
159: * Spin for indicated number of microseconds.
160: */
161: void IODelay(unsigned microseconds)
162: {
163: ns_time_t currentTime;
164: ns_time_t endTime;
165: unsigned diff;
166:
167: IOGetTimestamp(&endTime);
168: endTime += ((ns_time_t)microseconds * 1000);
169: while(1) {
170: IOGetTimestamp(¤tTime);
171: diff = (unsigned)(endTime - currentTime);
172: if((int)(diff) < 0) {
173: return;
174: }
175: }
176: }
177:
178: /*
179: * Call function fcn with argument arg in specified number of seconds.
180: */
181: void IOScheduleFunc(IOThreadFunc fcn, void *arg, int seconds)
182: {
183: ioCallout_t *callout;
184: ns_time_t ns = 0;
185:
186: /*
187: * Enqueue this request. The calloutThread will eventually process
188: * it.
189: */
190: if(seconds == 0) {
191: (*fcn)(arg);
192: return;
193: }
194: callout = IOMalloc(sizeof(*callout));
195: callout->fcn = fcn;
196: callout->arg = arg;
197: [calloutLock lock];
198: IOGetTimestamp(&callout->calloutTime);
199: ns = seconds;
200: ns *= (1000 * 1000 * 1000);
201: callout->calloutTime += ns;
202: xpr_libio("IOScheduleFunc(%d): making request\n",
203: seconds, 2,3,4,5);
204: queue_enter(&calloutChain,
205: callout,
206: ioCallout_t *,
207: link);
208: [calloutLock unlock];
209: return;
210: }
211:
212: /*
213: * This thread's job is to wake up once a second, scan the calloutChain, and
214: * do callouts for each entry whose time has come. This is pretty inefficient
215: * (yet another thread waiting around, running every second...). Maybe we can
216: * do better in the future.
217: *
218: * FIXME - this doesn't work. The libc long long support seems to be broken...
219: */
220: static void calloutThread(void *foo)
221: {
222: ioCallout_t *callout, *calloutNext;
223: ns_time_t currentTime;
224:
225: while(1) {
226: [calloutLock lock];
227: callout = (ioCallout_t *)queue_first(&calloutChain);
228: while(!queue_end(&calloutChain, (queue_t)callout)) {
229: calloutNext = (ioCallout_t *)callout->link.next;
230: IOGetTimestamp(¤tTime);
231: xpr_libio("calloutThread: currentTime %u:%u\n",
232: (unsigned)(currentTime / 0x100000000ULL),
233: (unsigned)(currentTime && 0xffffffff), 3,4,5);
234: if(currentTime >= callout->calloutTime) {
235: xpr_libio("calloutThread: doing callout\n",
236: 1,2,3,4,5);
237: queue_remove(&calloutChain,
238: callout,
239: ioCallout_t *,
240: link);
241: [calloutLock unlock];
242: (*callout->fcn)(callout->arg);
243: IOFree(callout, sizeof(*callout));
244: [calloutLock lock];
245: }
246: callout = calloutNext;
247: }
248: [calloutLock unlock];
249: IOSleep(1000);
250: }
251: /* NOT REACHED */
252: }
253:
254:
255: /*
256: * Cancel callout requested in IOScheduleFunc().
257: */
258: void IOUnscheduleFunc(IOThreadFunc fcn, void *arg)
259: {
260: ioCallout_t *callout;
261:
262: [calloutLock lock];
263: callout = (ioCallout_t *)queue_first(&calloutChain);
264: while(!queue_end(&calloutChain, (queue_t)callout)) {
265: if((callout->fcn == fcn) && (callout->arg == arg)) {
266: queue_remove(&calloutChain,
267: callout,
268: ioCallout_t *,
269: link);
270: IOFree(callout, sizeof(*callout));
271: goto done;
272: }
273: callout = (ioCallout_t *)callout->link.next;
274: }
275: xpr_libio("IOUnTimeout: callout not registered\n", 1,2,3,4,5);
276: done:
277: [calloutLock unlock];
278: return;
279: }
280:
281: /*
282: * Obtain current time in nanoseconds.
283: */
284:
285: static inline ns_time_t
286: tsval_to_ns_time(struct tsval *tsp)
287: {
288: ns_time_t a_time;
289:
290: a_time = ((ns_time_t)tsp->high_val) << 32;
291: a_time += tsp->low_val;
292: a_time *= 1000;
293:
294: return a_time;
295: }
296:
297:
298: void IOGetTimestamp(ns_time_t *nsp)
299: {
300: struct tsval ts;
301: ns_time_t ns;
302:
303: kern_timestamp(&ts);
304: #if 0
305: ns = tsval_to_ns_time(&ts);
306: #else 0
307: ns = ((ns_time_t)ts.high_val) * 0x100000000ULL;
308: ns += ts.low_val;
309: ns *= 1000;
310: #endif 0
311: *nsp = ns;
312: }
313:
314: void IOLog(const char *format, ...)
315: {
316: va_list ap;
317: char buf[300];
318:
319: va_start(ap, format);
320: vsprintf(buf, format, ap);
321: syslog(LOG_ERR, "%s", buf);
322: va_end(ap);
323: }
324:
325: void IOPanic(const char *reason)
326: {
327: IOLog(reason);
328: IOLog("waiting for debugger connection...");
329: /* FIXME */
330: while(1)
331: ;
332: }
333:
334: /*
335: * Convert a integer constant (typically a #define or enum) to a string.
336: */
337: static char noValue[80];
338:
339: const char *IOFindNameForValue(int value, const IONamedValue *regValueArray)
340: {
341: for( ; regValueArray->name; regValueArray++) {
342: if(regValueArray->value == value)
343: return(regValueArray->name);
344: }
345: sprintf(noValue, "%d(d) (UNDEFINED)", value);
346: return((const char *)noValue);
347: }
348:
349: IOReturn IOFindValueForName(const char *string,
350: const IONamedValue *regValueArray,
351: int *value)
352: {
353: for( ; regValueArray->name; regValueArray++) {
354: if(!strcmp(regValueArray->name, string)) {
355: *value = regValueArray->value;
356: return IO_R_SUCCESS;
357: }
358: }
359: return IO_R_INVALID_ARG;
360: }
361:
362: /*
363: * One-time only init for this module.
364: */
365: void IOInitGeneralFuncs()
366: {
367: queue_init(&calloutChain);
368: calloutLock = [NXLock new];
369: if(port_allocate(task_self(), &sleepPort) != KERN_SUCCESS) {
370: IOLog("IOInitGeneralFunc: port_allocate error\n");
371: }
372: IOForkThread((IOThreadFunc)&calloutThread, NULL);
373: }
374:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.