Example #1
0
Status ModuleShutdown(volatile ModuleInitState* initState, void (*shutdown)())
{
	for(;;)
	{
		if(cpu_CAS(initState, INITIALIZED, BUSY))
		{
			shutdown();
			*initState = UNINITIALIZED;
			COMPILER_FENCE;
			return INFO::OK;
		}

		const ModuleInitState latchedInitState = *initState;
		if(latchedInitState == INITIALIZED || latchedInitState == BUSY)
		{
			cpu_Pause();
			continue;
		}

		if(latchedInitState == UNINITIALIZED)
			return INFO::SKIPPED;

		ENSURE(latchedInitState < 0);
		return (Status)latchedInitState;
	}
}
Example #2
0
int pthread_key_create(pthread_key_t* key, void (*dtor)(void*))
{
	DWORD idx = TlsAlloc();
	if(idx == TLS_OUT_OF_INDEXES)
		return -ENOMEM;

	ENSURE(idx < TLS_LIMIT);
	*key = (pthread_key_t)idx;

	// acquire a free dtor slot
	size_t i;
	for(i = 0; i < MAX_DTORS; i++)
	{
		if(cpu_CAS((volatile intptr_t*)&dtors[i].dtor, (intptr_t)0, (intptr_t)dtor))
			goto have_slot;
	}

	// not enough slots; we have a valid key, but its dtor won't be called.
	WARN_IF_ERR(ERR::LIMIT);
	return -1;

have_slot:
	dtors[i].key = *key;
	return 0;
}
Example #3
0
// NB: callers should skip this if *idxDeleterOut != 0 (avoids the overhead
// of an unnecessary indirect function call)
void RegisterUniqueRangeDeleter(UniqueRangeDeleter deleter, volatile IdxDeleter* idxDeleterOut)
{
	ENSURE(deleter);

	if(!cpu_CAS(idxDeleterOut, idxDeleterNone, -1))	// not the first call for this deleter
	{
		// wait until an index has been assigned
		while(*idxDeleterOut <= 0)
			cpu_Pause();
		return;
	}

	const IdxDeleter idxDeleter = cpu_AtomicAdd(&numDeleters, 1);
	ENSURE(idxDeleter < (IdxDeleter)ARRAY_SIZE(deleters));
	deleters[idxDeleter] = deleter;
	COMPILER_FENCE;
	*idxDeleterOut = idxDeleter;
}
Example #4
0
File: debug.cpp Project: 2asoft/0ad
Status debug_WriteCrashlog(const wchar_t* text)
{
	// (avoid infinite recursion and/or reentering this function if it
	// fails/reports an error)
	enum State
	{
		IDLE,
		BUSY,
		FAILED
	};
	// note: the initial state is IDLE. we rely on zero-init because
	// initializing local static objects from constants may happen when
	// this is first called, which isn't thread-safe. (see C++ 6.7.4)
	cassert(IDLE == 0);
	static volatile intptr_t state;

	if(!cpu_CAS(&state, IDLE, BUSY))
		return ERR::REENTERED;	// NOWARN

	OsPath pathname = ah_get_log_dir()/"crashlog.txt";
	FILE* f = sys_OpenFile(pathname, "w");
	if(!f)
	{
		state = FAILED;	// must come before DEBUG_DISPLAY_ERROR
		DEBUG_DISPLAY_ERROR(L"Unable to open crashlog.txt for writing (please ensure the log directory is writable)");
		return ERR::FAIL;	// NOWARN (the above text is more helpful than a generic error code)
	}

	fputwc(0xFEFF, f);	// BOM
	fwprintf(f, L"%ls\n", text);
	fwprintf(f, L"\n\n====================================\n\n");

	// allow user to bundle whatever information they want
	ah_bundle_logs(f);

	fclose(f);
	state = IDLE;
	return INFO::OK;
}
Example #5
0
Status ModuleInit(volatile ModuleInitState* initState, Status (*init)())
{
	for(;;)
	{
		if(cpu_CAS(initState, UNINITIALIZED, BUSY))
		{
			Status ret = init();
			*initState = (ret == INFO::OK)? INITIALIZED : ret;
			COMPILER_FENCE;
			return ret;
		}

		const ModuleInitState latchedInitState = *initState;
		if(latchedInitState == UNINITIALIZED || latchedInitState == BUSY)
		{
			cpu_Pause();
			continue;
		}

		ENSURE(latchedInitState == INITIALIZED || latchedInitState < 0);
		return (Status)latchedInitState;
	}
}
Example #6
0
bool VfsDirectory::ShouldPopulate()
{
	return cpu_CAS(&m_shouldPopulate, 1, 0);	// test and reset
}
Example #7
0
void VfsDirectory::SetAssociatedDirectory(const PRealDirectory& realDirectory)
{
	if(!cpu_CAS(&m_shouldPopulate, 0, 1))
		DEBUG_WARN_ERR(ERR::LOGIC);	// caller didn't check ShouldPopulate
	m_realDirectory = realDirectory;
}
Example #8
0
int pthread_once(pthread_once_t* once, void (*init_routine)())
{
	if(cpu_CAS((volatile intptr_t*)once, 0, 1))
		init_routine();
	return 0;
}