File:  [Apple Darwin 0.x] / driverkit / Examples / ioThread / ioThread.m
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:37:50 2018 UTC (8 years, 3 months ago) by root
Branches: MAIN, Apple
CVS tags: HEAD, Darwin03, Darwin02
Darwin 0.2 Driver Kit

/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.1 (the "License").  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/*
 * ioThread.m - I/O thread example. 
 *
 * This example consists of a simple driver class with one I/O thread. 
 * Exported methods are invoked interactively via stdin. These methods 
 * pass commands to the I/O thread, which performs various trivial tasks
 * and then notifies the exported methods of command complete.
 */

#include "ioThread.h"
#include "ioThreadPrivate.h"
 
static void MyDeviceThread(id deviceId);

/*
 * A regular old Unix-y program to exercise the MyDevice class.
 */
int main(int argc, char **argv)
{
	id devId;
	char in_string[40];
	int aNumber;
	
	/*
	 * Create and initialize one instance of MyDevice. Forget devPort
	 * for this example.
	 */
	devId = [MyDevice alloc];
	[devId myDeviceInit];
	
	/*
	 * Main I/O loop. We'll invoke the exported methods on myDevice 
	 * per user input.
	 */
	 
	while(1) {
		printf("Main Loop:\n");
		printf("  p  print number\n");
		printf("  g  get number\n");
		printf("  q  quit program\n\n");
		printf("Enter Selection: ");
		gets(in_string);
		switch(in_string[0]) {
		   case 'p':
		   	/*
			 * Get a number, pass it throught to MyDevice's
			 * I/O thread for display.
			 */
		   	printf("\nEnter number to pass to I/O thread: ");
			gets(in_string);
			aNumber = atoi(in_string);
			[devId printNumber:aNumber];
			break;
			
		   case 'g':
		   	/*
			 * Get a number via MyDevice's I/O thread.
			 */
			aNumber = [devId getNumber];
			printf("getNumber returned %d\n", aNumber);
			break;
						
		   case 'q':
		   	/*
			 * Shut down.
			 */
		   	[devId free];
			exit(0);
			
		   default:
		   	printf("**Illegal Selection\n");
			break;
		}
	}
	
	/* NOT REACHED */
}

/*
 * Implementation of simple device.
 */
@implementation MyDevice

/*
 * Initialization.
 */
- myDeviceInit
{
	/*
	 * Initialize instance variables.
	 */
	ioQueueLock = [NXConditionLock new];
	queue_init(&ioQueue);
	
	/*
	 * Start up the I/O thread.
	 */
	ioThread = IOForkThread((IOThreadFunc)MyDeviceThread, self);

	/*
	 * Register with IODevice-level code.
	 */
	[self setName:"myDevice"];
	[super init];
	[self registerDevice];
	return self;
}

/*
 * Run-time methods.
 */
 
/*
 * Have I/O thread get a number from user.
 */
- (int)getNumber
{
	cmdBuf_t *cmdBuf;
	int result;
	
	/*
	 * Set up a cmdBuf.
	 */
	cmdBuf = [self cmdBufAlloc];
	cmdBuf->cmd = IOC_GETNUM;
	
	/*
	 * Pass the cmdBuf to the I/O thread. On return, the desired
	 * number is in cmdBuf.aNumber.
	 */
	[self cmdBufExec:cmdBuf];
	result = cmdBuf->aNumber;
	[self cmdBufFree:cmdBuf];
	return result;
}

/*
 * Have I/O thread print a number.
 */
- (void)printNumber : (int)aNumber
{
	cmdBuf_t *cmdBuf;
	
	/*
	 * Set up a cmdBuf.
	 */
	cmdBuf = [self cmdBufAlloc];
	cmdBuf->cmd = IOC_PRINTNUM;
	cmdBuf->aNumber = aNumber;
	
	/*
	 * Pass the cmdBuf to the I/O thread.
	 */
	[self cmdBufExec:cmdBuf];
	[self cmdBufFree:cmdBuf];
	return;
}

/*
 * Have I/O thread shut down cleanly.
 */
- free
{
	cmdBuf_t *cmdBuf;
	
	/*
	 * Set up a cmdBuf.
	 */
	cmdBuf = [self cmdBufAlloc];
	cmdBuf->cmd = IOC_QUIT;
	
	/*
	 * Pass the cmdBuf to the I/O thread.
	 */
	[self cmdBufExec:cmdBuf];
	[self cmdBufFree:cmdBuf];

	/*
	 * Free instance variables.
	 */	
	[ioQueueLock free];
	
	/*
	 * Have superclass take care of the rest.
	 */
	return [super free];
}


/*
 * Methods invoked by ioThread.
 */
 
/*
 * Wait for a work to appear in ioQueue.
 */
- (cmdBuf_t *)waitForCmdBuf
{
	cmdBuf_t *cmdBuf;
	
 	[ioQueueLock lockWhen:QUEUE_FULL];

	/*
	 * At this point, we still hold ioQueueLock'. Remove 
	 * the first element in ioQueue.
	 */
	cmdBuf = (cmdBuf_t *)queue_first(&ioQueue);
	queue_remove(&ioQueue,
		cmdBuf,
		cmdBuf_t *,
		link);
		
	/*
	 * Release ioQueueLock, updating its condition variable as 
	 * appropriate, and return the new cmdBuf to the ioThread.
	 */
	if(queue_empty(&ioQueue))
		[ioQueueLock unlockWith:QUEUE_EMPTY];
	else
		[ioQueueLock unlockWith:QUEUE_FULL];
	return cmdBuf;
}

/*
 * Notify client of I/O complete.
 */
- (void)cmdBufComplete : (cmdBuf_t *)cmdBuf
{
	[cmdBuf->cmdLock lock];
	[cmdBuf->cmdLock unlockWith:CMD_COMPLETE];
}

@end



/*
 * Private methods.
 */
 
@implementation MyDevice ( MyDevicePrivate )

/*
 * Create and initialize a new cmdBuf_t.
 */
- (cmdBuf_t *)cmdBufAlloc
{
	cmdBuf_t *cmdBuf;
	
	cmdBuf = IOMalloc(sizeof(cmdBuf_t));
	cmdBuf->cmdLock = [NXConditionLock new];
	[cmdBuf->cmdLock lock];
	[cmdBuf->cmdLock unlockWith:CMD_BUSY];
	return cmdBuf;
}

/*
 * Free a cmdBuf_t.
 */
- (void)cmdBufFree : (cmdBuf_t *)cmdBuf
{
	[cmdBuf->cmdLock free];
	IOFree(cmdBuf, sizeof(cmdBuf_t));
}

/*
 * Pass a cmdBuf to the I/O thread and wait for completion.
 */
- (void)cmdBufExec : (cmdBuf_t *)cmdBuf
{
	/*
	 * Add the cmdBuf to the ioQueue and let the ioThread know it has 
	 * work to do.
	 */
	[ioQueueLock lock];
	queue_enter(&ioQueue,
		cmdBuf,
		cmdBuf_t *,
		link);
	[ioQueueLock unlockWith:QUEUE_FULL];
	
	/*
	 * Wait for I/O complete.
	 */
	[cmdBuf->cmdLock lockWhen:CMD_COMPLETE];
	[cmdBuf->cmdLock unlock];
	
	return;
}

@end


/*
 * The I/O thread. This thread sits around waiting for work to do on
 * the ioQueue, then behaves accordingly.
 */
static void MyDeviceThread(id deviceId)
{
	cmdBuf_t *cmdBuf;
	char in_string[40];
	
	while(1) {
		
		/*
		 * Wait for something to do.
		 */
		cmdBuf = [deviceId waitForCmdBuf];
		
		/*
		 * OK, What's up?
		 */
		switch(cmdBuf->cmd) {
		    case IOC_GETNUM:
		    	/*
			 * Get a number from user, pass back to client.
			 */
		    	printf("MyDeviceThread: Enter number: ");
			gets(in_string);
			cmdBuf->aNumber = atoi(in_string);
			break;
			
		    case IOC_PRINTNUM:
		    	/*
			 * Just display client's number.
			 */
		    	printf("MyDeviceThread: cmdBuf->aNumber = %d\n",
				cmdBuf->aNumber);
			break;
			
		    case IOC_QUIT:
		    	/*
			 * Time to die. First notify client that we got 
			 * the command, then terminate.
			 */
			[deviceId cmdBufComplete:cmdBuf];
			IOExitThread();
			 
		}
		
		/*
		 * Notify client of I/O complete.
		 */
		[deviceId cmdBufComplete:cmdBuf];
	}
	
	/* NOT REACHED */
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.