Computer Laboratory

tesla_store.c
Go to the documentation of this file.
1 
2 /*-
3  * Copyright (c) 2012 Jonathan Anderson
4  * Copyright (c) 2011, 2013 Robert N. M. Watson
5  * Copyright (c) 2011 Anil Madhavapeddy
6  * All rights reserved.
7  *
8  * This software was developed by SRI International and the University of
9  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
10  * ("CTSRD"), as part of the DARPA CRASH research programme.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  * notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  * notice, this list of conditions and the following disclaimer in the
19  * documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $Id$
34  */
35 
36 #include "tesla_internal.h"
37 
38 #ifndef _KERNEL
39 #include <errno.h>
40 
42 pthread_key_t pthread_key(void);
43 void tesla_pthread_destructor(void*);
44 #endif
45 
46 static struct tesla_store global_store = { .length = 0 };
47 
48 static void tesla_class_acquire(tesla_class*);
49 
50 #ifdef _KERNEL
51 static void
52 tesla_global_store_sysinit(__unused void *arg)
53 {
54  uint32_t error;
55 
56  error = tesla_store_init(&global_store, TESLA_CONTEXT_GLOBAL,
58  tesla_assert(error == TESLA_SUCCESS, ("tesla_store_init failed"));
59 }
60 SYSINIT(tesla_global_store, SI_SUB_TESLA, SI_ORDER_FIRST,
61  tesla_global_store_sysinit, NULL);
62 #endif
63 
64 int32_t
65 tesla_store_get(enum tesla_context context, uint32_t classes,
66  uint32_t instances, tesla_store* *storep)
67 {
68  assert(storep);
69 
70  tesla_store *store;
71 
72  switch (context) {
74  store = &global_store;
75  break;
76 
77  case TESLA_CONTEXT_THREAD: {
78 #ifdef _KERNEL
79  store = curthread->td_tesla;
80 #else
81  pthread_key_t key = pthread_key();
82  store = pthread_getspecific(key);
83 #endif
84 
85  // Create a new store if we don't already have one.
86  if (store == NULL) {
87  store = tesla_malloc(sizeof(tesla_store));
88 #ifdef _KERNEL
89  curthread->td_tesla = store;
90 #else
91  __debug int err = pthread_setspecific(key, store);
92  assert(err == 0);
93 #endif
94  }
95  break;
96  }
97 
98  default:
99  return (TESLA_ERROR_EINVAL);
100  }
101 
102  if (store->length == 0) {
103  int32_t error =
104  tesla_store_init(store, context, classes, instances);
105 
106  if (error != TESLA_SUCCESS) return (error);
107 
108  assert(store->classes != NULL);
109  }
110 
111  *storep = store;
112  return (TESLA_SUCCESS);
113 }
114 
115 
116 int32_t
118  uint32_t classes, uint32_t instances)
119 {
120  assert(classes > 0);
121  assert(instances > 0);
122 
123  store->length = classes;
124  store->classes = tesla_malloc(classes * sizeof(tesla_class));
125  if (store->classes == NULL)
126  return (TESLA_ERROR_ENOMEM);
127 
128  int error = TESLA_SUCCESS;
129  for (uint32_t i = 0; i < classes; i++) {
130  error = tesla_class_init(store->classes + i, context, instances);
131  assert(error == TESLA_SUCCESS);
132  if (error != TESLA_SUCCESS)
133  break;
134 
135  assert(store->classes[i].tc_context >= 0);
136  }
137 
138  return (error);
139 }
140 
141 
142 void
144 {
145  DEBUG(libtesla.store.free, "tesla_store_free %tx\n", store);
146 
147  for (uint32_t i = 0; i < store->length; i++)
148  tesla_class_destroy(store->classes + i);
149 
150  tesla_free(store);
151 }
152 
153 
154 int32_t
155 tesla_class_get(tesla_store *store, uint32_t id, tesla_class **tclassp,
156  const char *name, const char *description)
157 {
158  assert(store != NULL);
159  assert(tclassp != NULL);
160 
161  if (id >= store->length)
162  return (TESLA_ERROR_EINVAL);
163 
164  tesla_class *tclass = &store->classes[id];
165  assert(tclass != NULL);
166  assert(tclass->tc_instances != NULL);
167  assert(tclass->tc_context >= 0);
168 
169  if (tclass->tc_name == NULL) tclass->tc_name = name;
170  if (tclass->tc_description == NULL)
171  tclass->tc_description = description;
172 
173  tesla_class_acquire(tclass);
174 
175  *tclassp = tclass;
176  return (TESLA_SUCCESS);
177 }
178 
179 void
180 tesla_class_acquire(tesla_class *class) {
181  switch (class->tc_context) {
183  return tesla_class_global_acquire(class);
184 
186  return tesla_class_perthread_acquire(class);
187 
188  default:
189  assert(0 && "unhandled TESLA context");
190  }
191 }
192 
193 #ifndef _KERNEL
194 pthread_key_t
196 {
197  // This function is just a singleton accessor.
198  static pthread_key_t key;
199  static int key_initialised = 0;
200  static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
201 
202  // The key, once initialised, is immutable, so it is safe to check and
203  // return it without locking. Multiple initialisations are prevented by
204  // the critical section below.
205  if (key_initialised) return key;
206 
207  int error __debug = pthread_mutex_lock(&lock);
208  assert(error == 0 && "failed to lock pthread key mutex");
209 
210  // Now that we're in the critical section, check again to make sure we
211  // initialise the key twice.
212  if (key_initialised) return key;
213 
214  error = pthread_key_create(&key, tesla_pthread_destructor);
215  assert(error == 0 && "failed to create pthread_key_t");
216 
217  key_initialised = 1;
218 
219  error = pthread_mutex_unlock(&lock);
220  assert(error == 0 && "failed to unlock pthread key mutex");
221 
222  return key;
223 }
224 
225 void
227 {
228  tesla_store *store = (tesla_store*) x;
229  tesla_store_free(store);
230 }
231 #endif
232