OSStatus
MD_CriticalRegionCreate(MDCriticalRegionID * outCriticalRegionID)
{
  MDCriticalRegionDataPtr newCriticalRegionPtr;
  MPSemaphoreID           mpSemaphoreID;
  OSStatus                err = noErr;

  if (outCriticalRegionID == NULL)
    return paramErr;

  *outCriticalRegionID = NULL;

  newCriticalRegionPtr = (MDCriticalRegionDataPtr)MPAllocateAligned(sizeof(MDCriticalRegionData),
                        kMPAllocateDefaultAligned, kMPAllocateClearMask);
  if (newCriticalRegionPtr == NULL)
    return memFullErr;

  // Note: this semaphore is pre-fired (ready!)
  err = MPCreateBinarySemaphore(&mpSemaphoreID);
  if (err == noErr)
  {
    newCriticalRegionPtr->mMPTaskID = kInvalidID;
    newCriticalRegionPtr->mDepthCount = 0;
    newCriticalRegionPtr->mMPSemaphoreID = mpSemaphoreID;

    *outCriticalRegionID = (MDCriticalRegionID)newCriticalRegionPtr;
  }
  else
  {
    MPFree((LogicalAddress)newCriticalRegionPtr);
  }

  return err;
}
static OSStatus HTTPServerProc(void *param)
	// This routine is the initial start routine for the server's 
	// preemptive thread.  It unpacks the parameters from the 
	// context then calls our HTTP server module to execute the server.
{
	OSStatus 	  err;
	ServerContext *context;
	
	context = (ServerContext *) param;

	err = RunHTTPServerMP(context->ipAddr, context->rootVRefNum, context->rootDirID);

	MPFree(context);
	
	return err;
}
OSStatus
MD_CriticalRegionDelete(MDCriticalRegionID inCriticalRegionID)
{
  MDCriticalRegionDataPtr criticalRegion = (MDCriticalRegionDataPtr)inCriticalRegionID;
  OSStatus                err = noErr;

  if (criticalRegion == NULL)
    return paramErr;

  if ((criticalRegion->mMPTaskID != kInvalidID) && (criticalRegion->mDepthCount > 0))
    return kMPInsufficientResourcesErr;

  if (criticalRegion->mMPSemaphoreID != kInvalidID)
    err = MPDeleteSemaphore(criticalRegion->mMPSemaphoreID);
  if (noErr != err) return err;

  criticalRegion->mMPSemaphoreID = kInvalidID;
  MPFree((LogicalAddress) criticalRegion);

  return noErr;
}
void NewAlloc::operator delete(void* p)
{
	MPFree(p);
}
static OSStatus RunOneServer(InetHost ipAddr)
	// This routine is the main line of the thread that runs
	// an HTTP server.  ipAddr is the address on which the
	// server is listening.
	//
	// The routine uses a directory whose name is the
	// dotted decimal string representation of ipAddr as the
	// root directory of the HTTP server.
{
	OSStatus 	err;
	OSStatus 	junk;
	Str255 		ipAddrString;
	FSSpec 		dirSpec;
	CInfoPBRec 	cpb;
	ServerContext *context;
	MPTaskID    junkServerThread;
	
	// Allocate a context for the preemptive thread.
	
	err = noErr;
	context = (ServerContext *) MPAllocateAligned(sizeof(*context), kMPAllocateDefaultAligned, kNilOptions);
	if (context == NULL) {
		err = memFullErr;
	}
	
	// Fill out the context.  We do this here because it needs 
	// to use services that aren't MP-safe.
	
	if (err == noErr) {
		context->ipAddr = ipAddr;
		
		// Get ipAddr as a dotted decimal Pascal string.
		OTInetHostToString(ipAddr, ((char *) ipAddrString) + 1);
		ipAddrString[0] = OTStrLength(((char *) ipAddrString) + 1);
		
		// Find the associated dirID, creating the directory
		// if necessary.

		junk = MoreProcGetCurrentProcessFSSpec(&dirSpec);
		assert(junk == noErr);
			
		(void) FSMakeFSSpec(dirSpec.vRefNum, dirSpec.parID, ipAddrString, &dirSpec);
		context->rootVRefNum = dirSpec.vRefNum;
		err = FSpGetCatInfo(&dirSpec, 0, &cpb);
		if (err == noErr && ( (cpb.hFileInfo.ioFlAttrib & (1 << 4)) != 0) ) {
			context->rootDirID = cpb.hFileInfo.ioDirID;
		} else {
			err = FSpDirCreate(&dirSpec, 0, (SInt32 *) &context->rootDirID);
		}
	}
	
	// Start a preemptive thread to run an HTTP server on the IP address.
	
	if (err == noErr) {
		err = MPCreateTask(HTTPServerProc, context, 65536, kInvalidID, NULL, NULL, kNilOptions, &junkServerThread);
		if (err == noErr) {
			context = NULL;				// it's now the task's responsibility
		}
	}
	if (context != NULL) {
		MPFree(context);
	}
	
	return err;
}