|
|
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.