mirror of
https://github.com/electronicarts/CnC_Renegade.git
synced 2025-12-17 16:11:40 -05:00
Initial commit of Command & Conquer Renegade source code.
This commit is contained in:
174
Code/wwlib/mutex.h
Normal file
174
Code/wwlib/mutex.h
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
** Command & Conquer Renegade(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MUTEX_H
|
||||
#define MUTEX_H
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "always.h"
|
||||
#include "thread.h"
|
||||
|
||||
|
||||
// Always use mutex or critical section when accessing the same data from multiple threads!
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Mutex class is an expensive way of synchronization! Use critical sections
|
||||
// (below) for all synchronization. Use mutexes for inter-process locking.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class MutexClass
|
||||
{
|
||||
void* handle;
|
||||
unsigned locked;
|
||||
|
||||
// Lock and unlock are private so that you can't use them directly. Use LockClass as a sentry instead!
|
||||
// Lock returns true if lock was succesful, false otherwise
|
||||
bool Lock(int time);
|
||||
void Unlock();
|
||||
|
||||
public:
|
||||
// Name can (and usually should) be NULL. Use name only if you wish to create a globally unique mutex
|
||||
MutexClass(const char* name = NULL);
|
||||
~MutexClass();
|
||||
|
||||
enum {
|
||||
WAIT_INFINITE=-1
|
||||
};
|
||||
|
||||
class LockClass
|
||||
{
|
||||
MutexClass& mutex;
|
||||
bool failed;
|
||||
public:
|
||||
|
||||
// In order to lock a mutex create a local instance of LockClass with mutex as a parameter.
|
||||
// Time is in milliseconds, INFINITE means infinite wait.
|
||||
LockClass(MutexClass& m, int time=MutexClass::WAIT_INFINITE);
|
||||
~LockClass();
|
||||
|
||||
// Returns true if the lock failed
|
||||
bool Failed() { return failed; }
|
||||
private:
|
||||
LockClass &operator=(const LockClass&) { return(*this); }
|
||||
};
|
||||
friend class LockClass;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Critical sections are faster than mutex classes and they should be used
|
||||
// for all synchronization.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class CriticalSectionClass
|
||||
{
|
||||
void* handle;
|
||||
unsigned locked;
|
||||
|
||||
// Lock and unlock are private so that you can't use them directly. Use LockClass as a sentry instead!
|
||||
void Lock();
|
||||
void Unlock();
|
||||
|
||||
public:
|
||||
// Name can (and usually should) be NULL. Use name only if you wish to create a globally unique mutex
|
||||
CriticalSectionClass();
|
||||
~CriticalSectionClass();
|
||||
|
||||
class LockClass
|
||||
{
|
||||
CriticalSectionClass& CriticalSection;
|
||||
public:
|
||||
// In order to lock a mutex create a local instance of LockClass with mutex as a parameter.
|
||||
LockClass(CriticalSectionClass& c);
|
||||
~LockClass();
|
||||
private:
|
||||
LockClass &operator=(const LockClass&) { return(*this); }
|
||||
};
|
||||
friend class LockClass;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Fast critical section is really fast version of CriticalSection. The downside
|
||||
// of it is that it can't be locked multiple times from the same thread.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class FastCriticalSectionClass
|
||||
{
|
||||
volatile unsigned Flag;
|
||||
|
||||
void Thread_Safe_Set_Flag()
|
||||
{
|
||||
volatile unsigned& nFlag=Flag;
|
||||
|
||||
#define ts_lock _emit 0xF0
|
||||
assert(((unsigned)&nFlag % 4) == 0);
|
||||
|
||||
__asm mov ebx, [nFlag]
|
||||
__asm ts_lock
|
||||
__asm bts dword ptr [ebx], 0
|
||||
__asm jc The_Bit_Was_Previously_Set_So_Try_Again
|
||||
return;
|
||||
|
||||
The_Bit_Was_Previously_Set_So_Try_Again:
|
||||
ThreadClass::Switch_Thread();
|
||||
__asm mov ebx, [nFlag]
|
||||
__asm ts_lock
|
||||
__asm bts dword ptr [ebx], 0
|
||||
__asm jc The_Bit_Was_Previously_Set_So_Try_Again
|
||||
}
|
||||
|
||||
WWINLINE void Thread_Safe_Clear_Flag()
|
||||
{
|
||||
Flag = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
// Name can (and usually should) be NULL. Use name only if you wish to create a globally unique mutex
|
||||
FastCriticalSectionClass() : Flag(0) {}
|
||||
|
||||
class LockClass
|
||||
{
|
||||
FastCriticalSectionClass& CriticalSection;
|
||||
public:
|
||||
LockClass(FastCriticalSectionClass& critical_section) : CriticalSection(critical_section)
|
||||
{
|
||||
CriticalSection.Thread_Safe_Set_Flag();
|
||||
}
|
||||
|
||||
~LockClass()
|
||||
{
|
||||
CriticalSection.Thread_Safe_Clear_Flag();
|
||||
}
|
||||
private:
|
||||
LockClass &operator=(const LockClass&) { return(*this); }
|
||||
};
|
||||
|
||||
friend class LockClass;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user