AVPKit
AtomicInteger.cpp
1 /*******************************************************************************
2  * Copyright (c) 2024, 2026, Olivier Ayache. All rights reserved.
3  *
4  * This file is part of AVPKit.
5  *
6  * AVPKit is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * AVPKit is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with AVPKit. If not, see <http://www.gnu.org/licenses/>.
18  *******************************************************************************/
19 
20 #include "AtomicInteger.h"
21 #include "JNIHelper.h"
22 
23 namespace com { namespace avpkit { namespace ferry {
24  jclass AtomicInteger::mClass = 0;
25  jmethodID AtomicInteger::mConstructorMethod = 0;
26  jmethodID AtomicInteger::mGetMethod = 0;
27  jmethodID AtomicInteger::mSetMethod = 0;
28  jmethodID AtomicInteger::mGetAndSetMethod = 0;
29  jmethodID AtomicInteger::mGetAndIncrementMethod = 0;
30  jmethodID AtomicInteger::mGetAndDecrementMethod = 0;
31  jmethodID AtomicInteger::mGetAndAddMethod = 0;
32  jmethodID AtomicInteger::mIncrementAndGetMethod = 0;
33  jmethodID AtomicInteger::mDecrementAndGetMethod = 0;
34  jmethodID AtomicInteger::mAddAndGetMethod = 0;
35  jmethodID AtomicInteger::mCompareAndSetMethod = 0;
36 
37  // static initialization
38  bool AtomicInteger::mInitialized = false;
39 
40  bool
41  AtomicInteger::init()
42  {
43  // have the JNIHelper initialize us once it gets a VM
44  if (!mInitialized)
45  {
46  JNIHelper::sRegisterInitializationCallback(initializeClass, 0);
47  mInitialized = true;
48  }
49  return mInitialized;
50  }
51  void
52  AtomicInteger::initializeClass(JavaVM*, void*)
53  {
54  JNIEnv *env=JNIHelper::sGetEnv();
55  if (env && !mClass)
56  {
57  // We're inside a JVM, let's get to work.
58  jclass cls=env->FindClass("java/util/concurrent/atomic/AtomicInteger");
59  if (cls)
60  {
61  // find our constructors
62  mConstructorMethod = env->GetMethodID(cls,
63  "<init>", "()V");
64  // and find all our methods
65  mGetMethod=env->GetMethodID(cls, "get", "()I");
66  mSetMethod=env->GetMethodID(cls, "set", "(I)V");
67  mGetAndSetMethod=env->GetMethodID(cls, "getAndSet", "(I)I");
68  mCompareAndSetMethod=env->GetMethodID(cls,
69  "compareAndSet", "(II)Z");
70  mGetAndIncrementMethod=env->GetMethodID(cls,
71  "getAndIncrement", "()I");
72  mGetAndDecrementMethod=env->GetMethodID(cls,
73  "getAndDecrement", "()I");
74  mGetAndAddMethod=env->GetMethodID(cls,
75  "getAndAdd", "(I)I");
76  mIncrementAndGetMethod=env->GetMethodID(cls,
77  "incrementAndGet", "()I");
78  mDecrementAndGetMethod=env->GetMethodID(cls,
79  "decrementAndGet", "()I");
80  mAddAndGetMethod=env->GetMethodID(cls,
81  "addAndGet", "(I)I");
82 
83  // keep a reference around
84  mClass = (jclass)env->NewWeakGlobalRef(cls);
85  }
86  }
87  }
88 
89  void
90  AtomicInteger::initializeObject()
91  {
92  // we can actually use the JNI stuff.
93  init();
94  mAtomicValue = 0;
95  mNonAtomicValue = 0;
96  JNIEnv *env=JNIHelper::sGetEnv();
97  if (env)
98  {
99  if (!mClass) {
100  // we're being called by a JNIHelper
101  // initialization callback, but before
102  // our own. Go ahead and call us.
103  AtomicInteger::initializeClass(JNIHelper::sGetVM(), 0);
104  }
105  if (mClass)
106  {
107  jobject newValue = env->NewObject(mClass, mConstructorMethod);
108  if (newValue)
109  {
110  mAtomicValue = env->NewGlobalRef(newValue);
111  env->DeleteLocalRef(newValue);
112  }
113  }
114  }
115  }
116 
117  AtomicInteger::AtomicInteger()
118  {
119  initializeObject();
120  }
121 
122  AtomicInteger::AtomicInteger(int32_t val)
123  {
124  mNonAtomicValue = 0;
125  mAtomicValue = 0;
126  initializeObject();
127  this->set(val);
128  }
129 
130  AtomicInteger::~AtomicInteger()
131  {
132  if (mAtomicValue)
133  {
134  JNIEnv *env=JNIHelper::sGetEnv();
135  if (env)
136  {
137  env->DeleteGlobalRef(mAtomicValue);
138  mAtomicValue = 0;
139  }
140  }
141  }
142 
143  int32_t
144  AtomicInteger::get()
145  {
146  JNIEnv *env=JNIHelper::sGetEnv();
147  int32_t val = 0;
148 
149  if (mAtomicValue && env)
150  val = env->CallIntMethod(mAtomicValue,
151  mGetMethod);
152  else
153  val = mNonAtomicValue;
154  return val;
155  }
156 
157  void
158  AtomicInteger::set(int32_t newval)
159  {
160  JNIEnv *env=JNIHelper::sGetEnv();
161 
162  if (mAtomicValue && env)
163  env->CallVoidMethod(mAtomicValue,
164  mSetMethod, newval);
165  else
166  mNonAtomicValue=newval;
167  }
168 
169  int32_t
170  AtomicInteger::getAndSet(int32_t newval)
171  {
172  JNIEnv *env=JNIHelper::sGetEnv();
173  int32_t retval = 0;
174 
175  if (mAtomicValue && env)
176  retval = env->CallIntMethod(mAtomicValue,
177  mGetAndSetMethod, newval);
178  else {
179  retval = mNonAtomicValue;
180  mNonAtomicValue = newval;
181  }
182  return retval;
183  }
184 
185  int32_t
186  AtomicInteger::getAndIncrement()
187  {
188  JNIEnv *env=JNIHelper::sGetEnv();
189  int32_t retval = 0;
190 
191  if (mAtomicValue && env)
192  retval = env->CallIntMethod(mAtomicValue,
193  mGetAndIncrementMethod);
194  else
195  retval = mNonAtomicValue++;
196  return retval;
197  }
198 
199  int32_t
200  AtomicInteger::getAndDecrement()
201  {
202  JNIEnv *env=JNIHelper::sGetEnv();
203  int32_t retval = 0;
204 
205  if (mAtomicValue && env)
206  retval = env->CallIntMethod(mAtomicValue,
207  mGetAndDecrementMethod);
208  else
209  retval = mNonAtomicValue--;
210  return retval;
211  }
212 
213  int32_t
214  AtomicInteger::getAndAdd(int32_t newval)
215  {
216  JNIEnv *env=JNIHelper::sGetEnv();
217  int32_t retval = 0;
218 
219  if (mAtomicValue && env)
220  retval = env->CallIntMethod(mAtomicValue,
221  mGetAndAddMethod, newval);
222  else {
223  retval = mNonAtomicValue;
224  mNonAtomicValue += newval;
225 
226  }
227  return retval;
228  }
229 
230  int32_t
231  AtomicInteger::incrementAndGet()
232  {
233  JNIEnv *env=JNIHelper::sGetEnv();
234  int32_t retval = 0;
235 
236  if (mAtomicValue && env)
237  retval = env->CallIntMethod(mAtomicValue,
238  mIncrementAndGetMethod);
239  else
240  retval = (++mNonAtomicValue);
241  return retval;
242  }
243 
244  int32_t
245  AtomicInteger::decrementAndGet()
246  {
247  JNIEnv *env=JNIHelper::sGetEnv();
248  int32_t retval = 0;
249 
250  if (mAtomicValue && env)
251  retval = env->CallIntMethod(mAtomicValue,
252  mDecrementAndGetMethod);
253  else
254  retval = (--mNonAtomicValue);
255  return retval;
256  }
257 
258  int32_t
259  AtomicInteger::addAndGet(int32_t newval)
260  {
261  JNIEnv *env=JNIHelper::sGetEnv();
262  int32_t retval = 0;
263 
264  if (mAtomicValue && env)
265  retval = env->CallIntMethod(mAtomicValue,
266  mAddAndGetMethod, newval);
267  else {
268  mNonAtomicValue += newval;
269  retval = mNonAtomicValue;
270  }
271  return retval;
272  }
273 
274  bool
275  AtomicInteger::compareAndSet(int32_t expected, int32_t update)
276  {
277  JNIEnv *env=JNIHelper::sGetEnv();
278  bool retval = false;
279 
280  if (mAtomicValue && env)
281  retval = env->CallBooleanMethod(mAtomicValue,
282  mCompareAndSetMethod, expected, update);
283  else {
284  retval = (mNonAtomicValue == expected);
285  if (retval)
286  {
287  mNonAtomicValue = update;
288  }
289  }
290  return retval;
291  }
292 
293  bool
295  {
296  return init() && mAtomicValue != 0;
297  }
298 
299 }}}
bool compareAndSet(int32_t expected, int32_t update)
Compare the current value to expected, and if they are equal, set the current value to update.
WARNING: Do not use logging in this class, and do not set any static file variables to values other t...