summaryrefslogtreecommitdiff
path: root/src/common/atomic.h
blob: 518d2e6ab3d66d4227412a9d0d17959bddaaa3f7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/**
 * This file is part of Hercules.
 * http://herc.ws - http://github.com/HerculesWS/Hercules
 *
 * Copyright (C) 2012-2020 Hercules Dev Team
 * Copyright (C) rAthena Project (www.rathena.org)
 *
 * Hercules 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 COMMON_ATOMIC_H
#define COMMON_ATOMIC_H

// Atomic Operations
// (Interlocked CompareExchange, Add .. and so on ..)
//
// Implementation varies / depends on:
// - Architecture
// - Compiler
// - Operating System
//
// our Abstraction is fully API-Compatible to Microsoft's implementation @ NT5.0+
//
#include "common/cbasetypes.h"

#if defined(_MSC_VER)
#include "common/winapi.h"

// This checks if C/C++ Compiler Version is 18.00
#if _MSC_VER < 1800

#if !defined(_M_X64)
// When compiling for windows 32bit, the 8byte interlocked operations are not provided by Microsoft
// (because they need at least i586 so its not generic enough.. ... )
forceinline int64 InterlockedCompareExchange64(volatile int64 *dest, int64 exch, int64 _cmp){
	_asm{
		lea esi,_cmp;
		lea edi,exch;

		mov eax,[esi];
		mov edx,4[esi];
		mov ebx,[edi];
		mov ecx,4[edi];
		mov esi,dest;

		lock CMPXCHG8B [esi];
	}
}

forceinline volatile int64 InterlockedIncrement64(volatile int64 *addend){
	__int64 old;
	do{
		old = *addend;
	}while(InterlockedCompareExchange64(addend, (old+1), old) != old);

	return (old + 1);
}

forceinline volatile int64 InterlockedDecrement64(volatile int64 *addend){
	__int64 old;

	do{
		old = *addend;
	}while(InterlockedCompareExchange64(addend, (old-1), old) != old);

	return (old - 1);
}

forceinline volatile int64 InterlockedExchangeAdd64(volatile int64 *addend, int64 increment){
	__int64 old;

	do{
		old = *addend;
	}while(InterlockedCompareExchange64(addend, (old + increment), old) != old);

	return old;
}

forceinline volatile int64 InterlockedExchange64(volatile int64 *target, int64 val){
	__int64 old;
	do{
		old = *target;
	}while(InterlockedCompareExchange64(target, val, old) != old);

	return old;
}

#endif //endif 32bit windows

#endif //endif _msc_ver check

#elif defined(__GNUC__)

// The __sync functions are available on x86 or ARMv6+
#if !defined(__x86_64__) && !defined(__i386__) \
	&& ( !defined(__ARM_ARCH_VERSION__) || __ARM_ARCH_VERSION__ < 6 )
#error Your Target Platfrom is not supported
#endif

static forceinline int64 InterlockedExchangeAdd64(volatile int64 *addend, int64 increment){
	return __sync_fetch_and_add(addend, increment);
}//end: InterlockedExchangeAdd64()

static forceinline int32 InterlockedExchangeAdd(volatile int32 *addend, int32 increment){
	return __sync_fetch_and_add(addend, increment);
}//end: InterlockedExchangeAdd()

static forceinline int64 InterlockedIncrement64(volatile int64 *addend){
	return __sync_add_and_fetch(addend, 1);
}//end: InterlockedIncrement64()

static forceinline int32 InterlockedIncrement(volatile int32 *addend){
	return __sync_add_and_fetch(addend, 1);
}//end: InterlockedIncrement()

static forceinline int64 InterlockedDecrement64(volatile int64 *addend){
	return __sync_sub_and_fetch(addend, 1);
}//end: InterlockedDecrement64()

static forceinline int32 InterlockedDecrement(volatile int32 *addend){
	return __sync_sub_and_fetch(addend, 1);
}//end: InterlockedDecrement()

static forceinline int64 InterlockedCompareExchange64(volatile int64 *dest, int64 exch, int64 cmp){
	return __sync_val_compare_and_swap(dest, cmp, exch);
}//end: InterlockedCompareExchange64()

static forceinline int32 InterlockedCompareExchange(volatile int32 *dest, int32 exch, int32 cmp){
	return __sync_val_compare_and_swap(dest, cmp, exch);
}//end: InterlockedCompareExchnage()

static forceinline int64 InterlockedExchange64(volatile int64 *target, int64 val){
	return __sync_lock_test_and_set(target, val);
}//end: InterlockedExchange64()

static forceinline int32 InterlockedExchange(volatile int32 *target, int32 val){
	return __sync_lock_test_and_set(target, val);
}//end: InterlockedExchange()

#endif //endif compiler decision

#endif /* COMMON_ATOMIC_H */