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 4821 : int NaClRefCountCtor(struct NaClRefCount *self) {
13 4821 : NaClLog(4, "NaClRefCountCtor(0x%08"NACL_PRIxPTR").\n", (uintptr_t) self);
14 4821 : self->ref_count = 1;
15 4821 : self->vtbl = (struct NaClRefCountVtbl *) NULL;
16 4821 : if (NaClFastMutexCtor(&self->mu)) {
17 4821 : self->vtbl = &kNaClRefCountVtbl;
18 4821 : return 1;
19 : }
20 0 : return 0;
21 4821 : }
22 :
23 1183 : static void NaClRefCountDtor(struct NaClRefCount *self) {
24 1183 : NaClLog(4, "NaClRefCountDtor(0x%08"NACL_PRIxPTR"), refcount %"NACL_PRIuS
25 : ", destroying.\n",
26 : (uintptr_t) self,
27 : 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 1183 : switch (self->ref_count) {
39 : case 0:
40 1183 : break;
41 : case 1:
42 0 : 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 : (uintptr_t) self);
48 0 : break;
49 : default:
50 0 : 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 : self->ref_count);
56 0 : }
57 :
58 1183 : NaClFastMutexDtor(&self->mu);
59 1183 : self->vtbl = (struct NaClRefCountVtbl const *) NULL;
60 1183 : }
61 :
62 : struct NaClRefCountVtbl const kNaClRefCountVtbl = {
63 : NaClRefCountDtor,
64 : };
65 :
66 86155 : struct NaClRefCount *NaClRefCountRef(struct NaClRefCount *nrcp) {
67 86155 : NaClLog(4, "NaClRefCountRef(0x%08"NACL_PRIxPTR").\n",
68 : (uintptr_t) nrcp);
69 86155 : NaClFastMutexLock(&nrcp->mu);
70 86155 : if (0 == ++nrcp->ref_count) {
71 0 : NaClLog(LOG_FATAL, "NaClRefCountRef integer overflow\n");
72 0 : }
73 86155 : NaClFastMutexUnlock(&nrcp->mu);
74 86155 : return nrcp;
75 : }
76 :
77 84570 : void NaClRefCountUnref(struct NaClRefCount *nrcp) {
78 84570 : int destroy;
79 :
80 84570 : NaClLog(4, "NaClRefCountUnref(0x%08"NACL_PRIxPTR").\n",
81 : (uintptr_t) nrcp);
82 84570 : NaClFastMutexLock(&nrcp->mu);
83 84570 : if (0 == nrcp->ref_count) {
84 0 : NaClLog(LOG_FATAL,
85 : ("NaClRefCountUnref on 0x%08"NACL_PRIxPTR
86 : ", refcount already zero!\n"),
87 : (uintptr_t) nrcp);
88 0 : }
89 84570 : destroy = (0 == --nrcp->ref_count);
90 84570 : NaClFastMutexUnlock(&nrcp->mu);
91 84570 : if (destroy) {
92 1183 : (*nrcp->vtbl->Dtor)(nrcp);
93 1183 : free(nrcp);
94 1183 : }
95 84570 : }
96 :
97 284 : void NaClRefCountSafeUnref(struct NaClRefCount *nrcp) {
98 284 : NaClLog(4, "NaClRefCountSafeUnref(0x%08"NACL_PRIxPTR").\n",
99 : (uintptr_t) nrcp);
100 284 : if (NULL == nrcp) {
101 258 : return;
102 : }
103 26 : NaClRefCountUnref(nrcp);
104 310 : }
105 :
106 3390 : void NaClRefCountLock(struct NaClRefCount *nrcp) {
107 3390 : NaClFastMutexLock(&nrcp->mu);
108 3390 : }
109 :
110 3389 : void NaClRefCountUnlock(struct NaClRefCount *nrcp) {
111 3389 : NaClFastMutexUnlock(&nrcp->mu);
112 3389 : }
|