Squash  0.7.0
object.c
1 /* Copyright (c) 2013 The Squash Authors
2  *
3  * Permission is hereby granted, free of charge, to any person
4  * obtaining a copy of this software and associated documentation
5  * files (the "Software"), to deal in the Software without
6  * restriction, including without limitation the rights to use, copy,
7  * modify, merge, publish, distribute, sublicense, and/or sell copies
8  * of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be
12  * included in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  *
23  * Authors:
24  * Evan Nemerson <evan@nemerson.com>
25  */
26 
27 #include <assert.h>
28 
29 #include "internal.h"
30 
31 #if defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER)
32 # define squash_atomic_inc(var) __sync_fetch_and_add(var, 1)
33 # define squash_atomic_dec(var) __sync_fetch_and_sub(var, 1)
34 # define squash_atomic_cas(var, orig, val) __sync_val_compare_and_swap(var, orig, val)
35 #elif defined(_WIN32)
36 # define squash_atomic_cas(var, orig, val) InterlockedCompareExchange(var, orig, val)
37 #else
38 SQUASH_MTX_DEFINE(atomic_ref)
39 
40 static unsigned int
41 squash_atomic_cas (volatile unsigned int* var,
42  unsigned int orig,
43  unsigned int val) {
44  unsigned int res;
45 
46  SQUASH_MTX_LOCK(atomic_ref);
47  res = *var;
48  if (res == orig)
49  *var = val;
50  SQUASH_MTX_UNLOCK(atomic_ref);
51 
52  return res;
53 }
54 #endif
55 
56 #if !defined(squash_atomic_inc)
57 static unsigned int
58 squash_atomic_inc (volatile unsigned int* var) {
59  while (true) {
60  unsigned int tmp = *var;
61  if (squash_atomic_cas (var, tmp, tmp + 1) == tmp) {
62  return tmp;
63  }
64  }
65 }
66 #endif /* defined(squash_atomic_inc) */
67 
68 #if !defined(squash_atomic_dec)
69 static unsigned int
70 squash_atomic_dec (volatile unsigned int* var) {
71  while (true) {
72  unsigned int tmp = *var;
73  assert (tmp > 0);
74  if (squash_atomic_cas (var, tmp, tmp - 1) == tmp) {
75  return tmp;
76  }
77  }
78 }
79 #endif /* defined(squash_atomic_dec) */
80 
205 void*
206 squash_object_ref (void* obj) {
207  SquashObject* object = (SquashObject*) obj;
208 
209  if (object == NULL)
210  return object;
211 
212  if (object->is_floating) {
213  if (squash_atomic_cas (&(object->is_floating), 1, 0) == 0) {
214  squash_atomic_inc (&(object->ref_count));
215  }
216  } else {
217  squash_atomic_inc (&(object->ref_count));
218  }
219 
220  return obj;
221 }
222 
236 void*
238  SquashObject* object = (SquashObject*) obj;
239 
240  if (object == NULL)
241  return object;
242 
243  return (squash_atomic_cas (&(object->is_floating), 1, 0) == 1) ? obj : NULL;
244 }
245 
254 void*
255 squash_object_unref (void* obj) {
256  SquashObject* object = (SquashObject*) obj;
257 
258  if (object == NULL)
259  return object;
260 
261  unsigned int ref_count = squash_atomic_dec (&(object->ref_count));
262 
263  if (ref_count == 1) {
264  if (object->destroy_notify != NULL) {
265  object->destroy_notify (obj);
266  }
267  return NULL;
268  } else {
269  return NULL;
270  }
271 }
272 
279 unsigned int
281  if (obj == NULL)
282  return 0;
283 
284  return ((SquashObject*) obj)->ref_count;
285 }
286 
301 void
302 squash_object_init (void* obj, bool is_floating, SquashDestroyNotify destroy_notify) {
303  SquashObject* object = (SquashObject*) obj;
304 
305  assert (object != NULL);
306 
307  object->ref_count = 1;
308  object->is_floating = is_floating;
309  object->destroy_notify = destroy_notify;
310 }
311 
324 void
326  assert (obj != NULL);
327 }
328 
void(* SquashDestroyNotify)(void *data)
Callback to be invoked when information data is no longer needed.
Definition: object.h:43
void * squash_object_ref_sink(void *obj)
Sink a floating reference if one exists.
Definition: object.c:237
void * squash_object_unref(void *obj)
Decrement the reference count on an object.
Definition: object.c:255
unsigned int squash_object_get_ref_count(void *obj)
Get the current reference count of an object.
Definition: object.c:280
void * squash_object_ref(void *obj)
Increment the reference count on an object.
Definition: object.c:206
void squash_object_destroy(void *obj)
Destroy an object.
Definition: object.c:325
void squash_object_init(void *obj, bool is_floating, SquashDestroyNotify destroy_notify)
Initialize a new object.
Definition: object.c:302