Skip to content

Commit 37fe04b

Browse files
committed
Thread Safe Resource Manager
1 parent b84ce5a commit 37fe04b

File tree

3 files changed

+527
-0
lines changed

3 files changed

+527
-0
lines changed

TSRM/TSRM.c

Lines changed: 364 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
1+
#include "TSRM.h"
2+
#include <stdio.h>
3+
4+
typedef struct _tsrm_tls_entry tsrm_tls_entry;
5+
6+
struct _tsrm_tls_entry {
7+
void **storage;
8+
int count;
9+
THREAD_T thread_id;
10+
tsrm_tls_entry *next;
11+
};
12+
13+
14+
typedef struct {
15+
size_t size;
16+
void (*ctor)(void *resource);
17+
void (*dtor)(void *resource);
18+
} tsrm_resource_type;
19+
20+
21+
/* The memory manager table */
22+
static tsrm_tls_entry **tsrm_tls_table;
23+
static int tsrm_tls_table_size;
24+
static ts_rsrc_id id_count;
25+
26+
/* The resource sizes table */
27+
static tsrm_resource_type *resource_types_table;
28+
static int resource_types_table_size;
29+
30+
31+
static MUTEX_T tsmm_mutex; /* thread-safe memory manager mutex */
32+
33+
/* Debug support */
34+
static int tsrm_debug(const char *format, ...);
35+
static int tsrm_debug_status;
36+
37+
38+
/* Startup TSRM (call once for the entire process) */
39+
int tsrm_startup(int expected_threads, int expected_resources, int debug_status)
40+
{
41+
tsrm_tls_table_size = expected_threads;
42+
tsrm_tls_table = (tsrm_tls_entry **) calloc(tsrm_tls_table_size, sizeof(tsrm_tls_entry *));
43+
if (!tsrm_tls_table) {
44+
return 0;
45+
}
46+
id_count=0;
47+
48+
resource_types_table_size = expected_resources;
49+
resource_types_table = (tsrm_resource_type *) calloc(resource_types_table_size, sizeof(tsrm_resource_type));
50+
if (!resource_types_table) {
51+
free(tsrm_tls_table);
52+
return 0;
53+
}
54+
55+
tsmm_mutex = tsrm_mutex_alloc();
56+
57+
tsrm_debug_status = debug_status;
58+
59+
tsrm_debug("Started up TSRM, %d expected threads, %d expected resources\n", expected_threads, expected_resources);
60+
return 1;
61+
}
62+
63+
64+
/* Shutdown TSRM (call once for the entire process) */
65+
void tsrm_shutdown()
66+
{
67+
int i;
68+
69+
if (tsrm_tls_table) {
70+
for (i=0; i<tsrm_tls_table_size; i++) {
71+
tsrm_tls_entry *p = tsrm_tls_table[i], *next_p;
72+
73+
while (p) {
74+
int j;
75+
76+
next_p = p->next;
77+
for (j=0; j<id_count; j++) {
78+
free(p->storage[j]);
79+
}
80+
free(p->storage);
81+
free(p);
82+
p = next_p;
83+
}
84+
}
85+
free(tsrm_tls_table);
86+
}
87+
if (resource_types_table) {
88+
free(resource_types_table);
89+
}
90+
tsrm_mutex_free(tsmm_mutex);
91+
tsrm_debug("Shutdown TSRM\n");
92+
}
93+
94+
95+
/* allocates a new thread-safe-resource id */
96+
TSRM_FUNC ts_rsrc_id ts_allocate_id(size_t size, void (*ctor)(void *resource), void (*dtor)(void *resource))
97+
{
98+
ts_rsrc_id new_id;
99+
int i;
100+
101+
tsrm_debug("Obtaining a new resource id, %d bytes\n", size);
102+
103+
tsrm_mutex_lock(tsmm_mutex);
104+
105+
/* obtain a resource id */
106+
new_id = id_count++;
107+
tsrm_debug("Obtained resource id %d\n", new_id);
108+
109+
/* store the new resource type in the resource sizes table */
110+
if (resource_types_table_size < id_count) {
111+
resource_types_table = (tsrm_resource_type *) realloc(resource_types_table, sizeof(tsrm_resource_type)*id_count);
112+
if (!resource_types_table) {
113+
return -1;
114+
}
115+
resource_types_table_size = id_count;
116+
}
117+
resource_types_table[new_id].size = size;
118+
resource_types_table[new_id].ctor = ctor;
119+
resource_types_table[new_id].dtor = dtor;
120+
121+
/* enlarge the arrays for the already active threads */
122+
for (i=0; i<tsrm_tls_table_size; i++) {
123+
tsrm_tls_entry *p = tsrm_tls_table[i];
124+
125+
while (p) {
126+
if (p->count < id_count) {
127+
int j;
128+
129+
p->storage = realloc(p->storage, sizeof(void *)*id_count);
130+
for (j=p->count; j<id_count; j++) {
131+
p->storage[j] = (void *) malloc(resource_types_table[j].size);
132+
}
133+
p->count = id_count;
134+
}
135+
p = p->next;
136+
}
137+
}
138+
tsrm_mutex_unlock(tsmm_mutex);
139+
140+
tsrm_debug("Successfully allocated new resource id %d\n", new_id);
141+
return new_id;
142+
}
143+
144+
145+
static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_T thread_id)
146+
{
147+
int i;
148+
149+
(*thread_resources_ptr) = (tsrm_tls_entry *) malloc(sizeof(tsrm_tls_entry));
150+
(*thread_resources_ptr)->storage = (void **) malloc(sizeof(void *)*id_count);
151+
(*thread_resources_ptr)->count = id_count;
152+
(*thread_resources_ptr)->thread_id = thread_id;
153+
(*thread_resources_ptr)->next = NULL;
154+
for (i=0; i<id_count; i++) {
155+
(*thread_resources_ptr)->storage[i] = (void *) malloc(resource_types_table[i].size);
156+
resource_types_table[i].ctor((*thread_resources_ptr)->storage[i]);
157+
}
158+
}
159+
160+
161+
/* fetches the requested resource for the current thread */
162+
void *ts_resource(ts_rsrc_id id)
163+
{
164+
THREAD_T thread_id = tsrm_thread_id();
165+
int hash_value;
166+
tsrm_tls_entry *thread_resources;
167+
void *resource;
168+
169+
tsrm_debug("Fetching resource id %d for thread %ld\n", id, (long) thread_id);
170+
tsrm_mutex_lock(tsmm_mutex);
171+
172+
hash_value = THREAD_HASH_OF(thread_id, tsrm_tls_table_size);
173+
thread_resources = tsrm_tls_table[hash_value];
174+
175+
if (!thread_resources) {
176+
allocate_new_resource(&tsrm_tls_table[hash_value], thread_id);
177+
thread_resources = tsrm_tls_table[hash_value];
178+
} else {
179+
do {
180+
if (thread_resources->thread_id == thread_id) {
181+
break;
182+
}
183+
if (thread_resources->next) {
184+
thread_resources = thread_resources->next;
185+
} else {
186+
allocate_new_resource(&thread_resources->next, thread_id);
187+
thread_resources = thread_resources->next;
188+
break;
189+
}
190+
} while (thread_resources);
191+
}
192+
193+
resource = thread_resources->storage[id];
194+
195+
tsrm_mutex_unlock(tsmm_mutex);
196+
197+
tsrm_debug("Successfully fetched resource id %d for thread id %ld - %x\n", id, (long) thread_id, (long) resource);
198+
return resource;
199+
}
200+
201+
202+
/* frees all resources allocated for the current thread */
203+
void ts_free_thread()
204+
{
205+
THREAD_T thread_id = tsrm_thread_id();
206+
int hash_value;
207+
tsrm_tls_entry *thread_resources;
208+
tsrm_tls_entry *last=NULL;
209+
210+
tsrm_mutex_lock(tsmm_mutex);
211+
hash_value = THREAD_HASH_OF(thread_id, tsrm_tls_table_size);
212+
thread_resources = tsrm_tls_table[hash_value];
213+
214+
while (thread_resources) {
215+
if (thread_resources->thread_id == thread_id) {
216+
int i;
217+
218+
for (i=0; i<thread_resources->count; i++) {
219+
resource_types_table[i].dtor(thread_resources->storage[i]);
220+
free(thread_resources->storage[i]);
221+
}
222+
free(thread_resources->storage);
223+
if (last) {
224+
last->next = thread_resources->next;
225+
} else {
226+
tsrm_tls_table[hash_value]=NULL;
227+
}
228+
free(thread_resources);
229+
break;
230+
}
231+
if (thread_resources->next) {
232+
last = thread_resources;
233+
thread_resources = thread_resources->next;
234+
}
235+
}
236+
tsrm_mutex_unlock(tsmm_mutex);
237+
}
238+
239+
240+
/* deallocates all occurrences of a given id */
241+
void ts_free_id(ts_rsrc_id id)
242+
{
243+
}
244+
245+
246+
247+
248+
/*
249+
* Utility Functions
250+
*/
251+
252+
/* Obtain the current thread id */
253+
TSRM_FUNC THREAD_T tsrm_thread_id(void)
254+
{
255+
#ifdef WIN32
256+
return GetCurrentThreadId();
257+
#elif defined(PTHREADS)
258+
return pthread_self();
259+
#elif defined(NSAPI)
260+
return systhread_current();
261+
#elif defined(PI3WEB)
262+
return PIThread_getCurrent();
263+
#endif
264+
}
265+
266+
267+
/* Allocate a mutex */
268+
TSRM_FUNC MUTEX_T tsrm_mutex_alloc( void )
269+
{
270+
MUTEX_T mutexp;
271+
272+
#ifdef WIN32
273+
mutexp = CreateMutex(NULL,FALSE,NULL);
274+
#elif defined(PTHREADS)
275+
mutexp = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
276+
pthread_mutex_init(mutexp,NULL);
277+
#elif defined(NSAPI)
278+
mutexp = crit_init();
279+
#elif defined(PI3WEB)
280+
mutexp = PIPlatform_allocLocalMutex();
281+
#endif
282+
#ifdef THR_DEBUG
283+
printf("Mutex created thread: %d\n",mythreadid());
284+
#endif
285+
return( mutexp );
286+
}
287+
288+
289+
/* Free a mutex */
290+
TSRM_FUNC void tsrm_mutex_free( MUTEX_T mutexp )
291+
{
292+
if (mutexp) {
293+
#ifdef WIN32
294+
CloseHandle(mutexp);
295+
#elif defined(PTHREADS)
296+
free(mutexp);
297+
#elif defined(NSAPI)
298+
crit_terminate(mutexp);
299+
#elif defined(PI3WEB)
300+
PISync_delete(mutexp)
301+
#endif
302+
}
303+
#ifdef THR_DEBUG
304+
printf("Mutex freed thread: %d\n",mythreadid());
305+
#endif
306+
}
307+
308+
309+
/* Lock a mutex */
310+
TSRM_FUNC int tsrm_mutex_lock( MUTEX_T mutexp )
311+
{
312+
//tsrm_debug("Mutex locked thread: %ld\n",tsrm_thread_id());
313+
#ifdef WIN32
314+
return WaitForSingleObject(mutexp,1000);
315+
#elif defined(PTHREADS)
316+
return pthread_mutex_lock(mutexp);
317+
#elif defined(NSAPI)
318+
return crit_enter(mutexp);
319+
#elif defined(PI3WEB)
320+
return PISync_lock(mutexp);
321+
#endif
322+
}
323+
324+
325+
/* Unlock a mutex */
326+
TSRM_FUNC int tsrm_mutex_unlock( MUTEX_T mutexp )
327+
{
328+
//tsrm_debug("Mutex unlocked thread: %ld\n",tsrm_thread_id());
329+
#ifdef WIN32
330+
return ReleaseMutex(mutexp);
331+
#elif defined(PTHREADS)
332+
return pthread_mutex_unlock(mutexp);
333+
#elif defined(NSAPI)
334+
return crit_exit(mutexp);
335+
#elif defined(PI3WEB)
336+
return PISync_unlock(mutexp);
337+
#endif
338+
}
339+
340+
341+
/*
342+
* Debug support
343+
*/
344+
345+
static int tsrm_debug(const char *format, ...)
346+
{
347+
if (tsrm_debug_status) {
348+
va_list args;
349+
int size;
350+
351+
va_start(args, format);
352+
size = vprintf(format, args);
353+
va_end(args);
354+
return size;
355+
} else {
356+
return 0;
357+
}
358+
}
359+
360+
361+
void tsrm_debug_set(int status)
362+
{
363+
tsrm_debug_status = status;
364+
}

0 commit comments

Comments
 (0)