⛏️ index : haiku.git

/*
 * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */

#include "RequestThread.h"

#include <new>

#include <TLS.h>

#include "FileSystem.h"
#include "ServerDefs.h"
#include "UserlandRequestHandler.h"
#include "Volume.h"


static const int32 sTLSVariable = tls_allocate();


// constructor
RequestThreadContext::RequestThreadContext(Volume* volume,
	KernelRequest* request)
	:
	fPreviousContext(NULL),
	fThread(NULL),
	fVolume(volume),
	fRequest(request)
{
	fThread = RequestThread::GetCurrentThread();
	if (fThread) {
		fPreviousContext = fThread->GetContext();
		fThread->SetContext(this);
	}

	volume->GetFileSystem()->InitRequestThreadContext(this);
}

// destructor
RequestThreadContext::~RequestThreadContext()
{
	if (fThread)
		fThread->SetContext(fPreviousContext);
}

// GetThread
RequestThread*
RequestThreadContext::GetThread() const
{
	return fThread;
}

// GetVolume
UserlandFS::Volume*
RequestThreadContext::GetVolume() const
{
	return fVolume;
}


// RequestThread

// constructor
RequestThread::RequestThread()
	: fThread(-1),
	  fFileSystem(NULL),
	  fPort(NULL),
	  fContext(NULL),
	  fTerminating(false)
{
}

// destructor
RequestThread::~RequestThread()
{
	PrepareTermination();
	Terminate();
	delete fPort;
}

// Init
status_t
RequestThread::Init(FileSystem* fileSystem)
{
	if (!fileSystem)
		return B_BAD_VALUE;
	// create the port
	fPort = new(std::nothrow) RequestPort(kRequestPortSize);
	if (!fPort)
		return B_NO_MEMORY;
	status_t error = fPort->InitCheck();
	if (error != B_OK)
		return error;
	// spawn the thread
	fThread = spawn_thread(_ThreadEntry, "request thread", B_NORMAL_PRIORITY,
		this);
	if (fThread < 0)
		return fThread;
	fFileSystem = fileSystem;
	return B_OK;
}

// Run
void
RequestThread::Run()
{
	resume_thread(fThread);
}

// PrepareTermination
void
RequestThread::PrepareTermination()
{
	if (fTerminating)
		return;
	fTerminating = true;
	if (fPort)
		fPort->Close();
}

// Terminate
void
RequestThread::Terminate()
{
	if (fThread >= 0) {
		int32 result;
		wait_for_thread(fThread, &result);
		fThread = -1;
	}
}

// GetPortInfo
const Port::Info*
RequestThread::GetPortInfo() const
{
	return (fPort ? fPort->GetPortInfo() : NULL);
}

// GetFileSystem
UserlandFS::FileSystem*
RequestThread::GetFileSystem() const
{
	return fFileSystem;
}

// GetPort
RequestPort*
RequestThread::GetPort() const
{
	return fPort;
}

// GetContext
RequestThreadContext*
RequestThread::GetContext() const
{
	return fContext;
}

// GetCurrentThread
RequestThread*
RequestThread::GetCurrentThread()
{
	return (RequestThread*)tls_get(sTLSVariable);
}

// SetContext
void
RequestThread::SetContext(RequestThreadContext* context)
{
	fContext = context;
}

// _ThreadEntry
int32
RequestThread::_ThreadEntry(void* data)
{
	return ((RequestThread*)data)->_ThreadLoop();
}

// _ThreadLoop
int32
RequestThread::_ThreadLoop()
{
	tls_set(sTLSVariable, this);
	if (!fTerminating) {
		UserlandRequestHandler handler(fFileSystem, false);
		return fPort->HandleRequests(&handler);
	}
	return B_OK;
}