|
|
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: /*
25: * ioThread.m - I/O thread example.
26: *
27: * This example consists of a simple driver class with one I/O thread.
28: * Exported methods are invoked interactively via stdin. These methods
29: * pass commands to the I/O thread, which performs various trivial tasks
30: * and then notifies the exported methods of command complete.
31: */
32:
33: #include "ioThread.h"
34: #include "ioThreadPrivate.h"
35:
36: static void MyDeviceThread(id deviceId);
37:
38: /*
39: * A regular old Unix-y program to exercise the MyDevice class.
40: */
41: int main(int argc, char **argv)
42: {
43: id devId;
44: char in_string[40];
45: int aNumber;
46:
47: /*
48: * Create and initialize one instance of MyDevice. Forget devPort
49: * for this example.
50: */
51: devId = [MyDevice alloc];
52: [devId myDeviceInit];
53:
54: /*
55: * Main I/O loop. We'll invoke the exported methods on myDevice
56: * per user input.
57: */
58:
59: while(1) {
60: printf("Main Loop:\n");
61: printf(" p print number\n");
62: printf(" g get number\n");
63: printf(" q quit program\n\n");
64: printf("Enter Selection: ");
65: gets(in_string);
66: switch(in_string[0]) {
67: case 'p':
68: /*
69: * Get a number, pass it throught to MyDevice's
70: * I/O thread for display.
71: */
72: printf("\nEnter number to pass to I/O thread: ");
73: gets(in_string);
74: aNumber = atoi(in_string);
75: [devId printNumber:aNumber];
76: break;
77:
78: case 'g':
79: /*
80: * Get a number via MyDevice's I/O thread.
81: */
82: aNumber = [devId getNumber];
83: printf("getNumber returned %d\n", aNumber);
84: break;
85:
86: case 'q':
87: /*
88: * Shut down.
89: */
90: [devId free];
91: exit(0);
92:
93: default:
94: printf("**Illegal Selection\n");
95: break;
96: }
97: }
98:
99: /* NOT REACHED */
100: }
101:
102: /*
103: * Implementation of simple device.
104: */
105: @implementation MyDevice
106:
107: /*
108: * Initialization.
109: */
110: - myDeviceInit
111: {
112: /*
113: * Initialize instance variables.
114: */
115: ioQueueLock = [NXConditionLock new];
116: queue_init(&ioQueue);
117:
118: /*
119: * Start up the I/O thread.
120: */
121: ioThread = IOForkThread((IOThreadFunc)MyDeviceThread, self);
122:
123: /*
124: * Register with IODevice-level code.
125: */
126: [self setName:"myDevice"];
127: [super init];
128: [self registerDevice];
129: return self;
130: }
131:
132: /*
133: * Run-time methods.
134: */
135:
136: /*
137: * Have I/O thread get a number from user.
138: */
139: - (int)getNumber
140: {
141: cmdBuf_t *cmdBuf;
142: int result;
143:
144: /*
145: * Set up a cmdBuf.
146: */
147: cmdBuf = [self cmdBufAlloc];
148: cmdBuf->cmd = IOC_GETNUM;
149:
150: /*
151: * Pass the cmdBuf to the I/O thread. On return, the desired
152: * number is in cmdBuf.aNumber.
153: */
154: [self cmdBufExec:cmdBuf];
155: result = cmdBuf->aNumber;
156: [self cmdBufFree:cmdBuf];
157: return result;
158: }
159:
160: /*
161: * Have I/O thread print a number.
162: */
163: - (void)printNumber : (int)aNumber
164: {
165: cmdBuf_t *cmdBuf;
166:
167: /*
168: * Set up a cmdBuf.
169: */
170: cmdBuf = [self cmdBufAlloc];
171: cmdBuf->cmd = IOC_PRINTNUM;
172: cmdBuf->aNumber = aNumber;
173:
174: /*
175: * Pass the cmdBuf to the I/O thread.
176: */
177: [self cmdBufExec:cmdBuf];
178: [self cmdBufFree:cmdBuf];
179: return;
180: }
181:
182: /*
183: * Have I/O thread shut down cleanly.
184: */
185: - free
186: {
187: cmdBuf_t *cmdBuf;
188:
189: /*
190: * Set up a cmdBuf.
191: */
192: cmdBuf = [self cmdBufAlloc];
193: cmdBuf->cmd = IOC_QUIT;
194:
195: /*
196: * Pass the cmdBuf to the I/O thread.
197: */
198: [self cmdBufExec:cmdBuf];
199: [self cmdBufFree:cmdBuf];
200:
201: /*
202: * Free instance variables.
203: */
204: [ioQueueLock free];
205:
206: /*
207: * Have superclass take care of the rest.
208: */
209: return [super free];
210: }
211:
212:
213: /*
214: * Methods invoked by ioThread.
215: */
216:
217: /*
218: * Wait for a work to appear in ioQueue.
219: */
220: - (cmdBuf_t *)waitForCmdBuf
221: {
222: cmdBuf_t *cmdBuf;
223:
224: [ioQueueLock lockWhen:QUEUE_FULL];
225:
226: /*
227: * At this point, we still hold ioQueueLock'. Remove
228: * the first element in ioQueue.
229: */
230: cmdBuf = (cmdBuf_t *)queue_first(&ioQueue);
231: queue_remove(&ioQueue,
232: cmdBuf,
233: cmdBuf_t *,
234: link);
235:
236: /*
237: * Release ioQueueLock, updating its condition variable as
238: * appropriate, and return the new cmdBuf to the ioThread.
239: */
240: if(queue_empty(&ioQueue))
241: [ioQueueLock unlockWith:QUEUE_EMPTY];
242: else
243: [ioQueueLock unlockWith:QUEUE_FULL];
244: return cmdBuf;
245: }
246:
247: /*
248: * Notify client of I/O complete.
249: */
250: - (void)cmdBufComplete : (cmdBuf_t *)cmdBuf
251: {
252: [cmdBuf->cmdLock lock];
253: [cmdBuf->cmdLock unlockWith:CMD_COMPLETE];
254: }
255:
256: @end
257:
258:
259:
260: /*
261: * Private methods.
262: */
263:
264: @implementation MyDevice ( MyDevicePrivate )
265:
266: /*
267: * Create and initialize a new cmdBuf_t.
268: */
269: - (cmdBuf_t *)cmdBufAlloc
270: {
271: cmdBuf_t *cmdBuf;
272:
273: cmdBuf = IOMalloc(sizeof(cmdBuf_t));
274: cmdBuf->cmdLock = [NXConditionLock new];
275: [cmdBuf->cmdLock lock];
276: [cmdBuf->cmdLock unlockWith:CMD_BUSY];
277: return cmdBuf;
278: }
279:
280: /*
281: * Free a cmdBuf_t.
282: */
283: - (void)cmdBufFree : (cmdBuf_t *)cmdBuf
284: {
285: [cmdBuf->cmdLock free];
286: IOFree(cmdBuf, sizeof(cmdBuf_t));
287: }
288:
289: /*
290: * Pass a cmdBuf to the I/O thread and wait for completion.
291: */
292: - (void)cmdBufExec : (cmdBuf_t *)cmdBuf
293: {
294: /*
295: * Add the cmdBuf to the ioQueue and let the ioThread know it has
296: * work to do.
297: */
298: [ioQueueLock lock];
299: queue_enter(&ioQueue,
300: cmdBuf,
301: cmdBuf_t *,
302: link);
303: [ioQueueLock unlockWith:QUEUE_FULL];
304:
305: /*
306: * Wait for I/O complete.
307: */
308: [cmdBuf->cmdLock lockWhen:CMD_COMPLETE];
309: [cmdBuf->cmdLock unlock];
310:
311: return;
312: }
313:
314: @end
315:
316:
317: /*
318: * The I/O thread. This thread sits around waiting for work to do on
319: * the ioQueue, then behaves accordingly.
320: */
321: static void MyDeviceThread(id deviceId)
322: {
323: cmdBuf_t *cmdBuf;
324: char in_string[40];
325:
326: while(1) {
327:
328: /*
329: * Wait for something to do.
330: */
331: cmdBuf = [deviceId waitForCmdBuf];
332:
333: /*
334: * OK, What's up?
335: */
336: switch(cmdBuf->cmd) {
337: case IOC_GETNUM:
338: /*
339: * Get a number from user, pass back to client.
340: */
341: printf("MyDeviceThread: Enter number: ");
342: gets(in_string);
343: cmdBuf->aNumber = atoi(in_string);
344: break;
345:
346: case IOC_PRINTNUM:
347: /*
348: * Just display client's number.
349: */
350: printf("MyDeviceThread: cmdBuf->aNumber = %d\n",
351: cmdBuf->aNumber);
352: break;
353:
354: case IOC_QUIT:
355: /*
356: * Time to die. First notify client that we got
357: * the command, then terminate.
358: */
359: [deviceId cmdBufComplete:cmdBuf];
360: IOExitThread();
361:
362: }
363:
364: /*
365: * Notify client of I/O complete.
366: */
367: [deviceId cmdBufComplete:cmdBuf];
368: }
369:
370: /* NOT REACHED */
371: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.