1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #include "native_client/src/trusted/nacl_base/nacl_refcount.h"
8 :
9 : #include "native_client/src/shared/platform/nacl_log.h"
10 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
11 :
12 6 : int NaClRefCountCtor(struct NaClRefCount *self) {
13 6 : NaClLog(4, "NaClRefCountCtor(0x%08"NACL_PRIxPTR").\n", (uintptr_t) self);
14 6 : self->ref_count = 1;
15 6 : self->vtbl = (struct NaClRefCountVtbl *) NULL;
16 6 : if (NaClFastMutexCtor(&self->mu)) {
17 6 : self->vtbl = &kNaClRefCountVtbl;
18 6 : return 1;
19 : }
20 0 : return 0;
21 6 : }
22 :
23 5 : static void NaClRefCountDtor(struct NaClRefCount *self) {
24 : NaClLog(4, "NaClRefCountDtor(0x%08"NACL_PRIxPTR"), refcount %"NACL_PRIuS
25 : ", destroying.\n",
26 : (uintptr_t) self,
27 5 : self->ref_count);
28 : /*
29 : * NB: refcount could be non-zero. Here's why: if a subclass's Ctor
30 : * fails, it will have already run NaClRefCountCtor and have
31 : * initialized the mutex and set the ref_count to 1. Because Unref
32 : * would free memory and Ctors aren't factories, the subclass Ctor
33 : * cannot just invoke NaClRefCountUnref; instead, it must directly
34 : * invoke the base class Dtor.
35 : *
36 : * We do, however, expect the ref_count to be either 0 or 1.
37 : */
38 5 : switch (self->ref_count) {
39 : case 0:
40 5 : break;
41 : case 1:
42 : NaClLog(LOG_WARNING,
43 : ("NaClRefCountDtor invoked on a generic refcounted"
44 : " object at 0x%08"NACL_PRIxPTR" with refcount 1."
45 : " This legitimately occurs only during subclass"
46 : " ctor failures.\n"),
47 0 : (uintptr_t) self);
48 0 : break;
49 : default:
50 : NaClLog(LOG_FATAL,
51 : ("NaClRefCountDtor invoked on a generic refcounted"
52 : " object at 0x%08"NACL_PRIxPTR" with non-zero"
53 : " reference count (%"NACL_PRIuS")\n"),
54 : (uintptr_t) self,
55 0 : self->ref_count);
56 : }
57 :
58 5 : NaClFastMutexDtor(&self->mu);
59 5 : self->vtbl = (struct NaClRefCountVtbl const *) NULL;
60 5 : }
61 :
62 : struct NaClRefCountVtbl const kNaClRefCountVtbl = {
63 : NaClRefCountDtor,
64 : };
65 :
66 4 : struct NaClRefCount *NaClRefCountRef(struct NaClRefCount *nrcp) {
67 : NaClLog(4, "NaClRefCountRef(0x%08"NACL_PRIxPTR").\n",
68 4 : (uintptr_t) nrcp);
69 4 : NaClFastMutexLock(&nrcp->mu);
70 4 : if (0 == ++nrcp->ref_count) {
71 0 : NaClLog(LOG_FATAL, "NaClRefCountRef integer overflow\n");
72 : }
73 4 : NaClFastMutexUnlock(&nrcp->mu);
74 4 : return nrcp;
75 4 : }
76 :
77 6 : void NaClRefCountUnref(struct NaClRefCount *nrcp) {
78 : int destroy;
79 :
80 : NaClLog(4, "NaClRefCountUnref(0x%08"NACL_PRIxPTR").\n",
81 6 : (uintptr_t) nrcp);
82 6 : NaClFastMutexLock(&nrcp->mu);
83 6 : if (0 == nrcp->ref_count) {
84 : NaClLog(LOG_FATAL,
85 : ("NaClRefCountUnref on 0x%08"NACL_PRIxPTR
86 : ", refcount already zero!\n"),
87 0 : (uintptr_t) nrcp);
88 : }
89 6 : destroy = (0 == --nrcp->ref_count);
90 6 : NaClFastMutexUnlock(&nrcp->mu);
91 6 : if (destroy) {
92 5 : (*nrcp->vtbl->Dtor)(nrcp);
93 5 : free(nrcp);
94 : }
95 6 : }
96 :
97 1 : void NaClRefCountSafeUnref(struct NaClRefCount *nrcp) {
98 : NaClLog(4, "NaClRefCountSafeUnref(0x%08"NACL_PRIxPTR").\n",
99 1 : (uintptr_t) nrcp);
100 1 : if (NULL == nrcp) {
101 0 : return;
102 : }
103 1 : NaClRefCountUnref(nrcp);
104 1 : }
105 :
106 3 : void NaClRefCountLock(struct NaClRefCount *nrcp) {
107 3 : NaClFastMutexLock(&nrcp->mu);
108 3 : }
109 :
110 3 : void NaClRefCountUnlock(struct NaClRefCount *nrcp) {
111 3 : NaClFastMutexUnlock(&nrcp->mu);
112 3 : }
|