aboutsummaryrefslogtreecommitdiff
path: root/src/Platform/Posix/Tss.c
blob: 87a5006a4225c07791e0abc83e47e1e10e4fb0a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include "Thread.h"

#include <stdlib.h>
#include <string.h>


static int tssCleanupLock = 0;
static int tssCleanupSize = 0;
static BH_GenericCallback tssCleanupData[BH_MAX_TSS];

static int tssLock = 0;
static int tssReady = 0;
static pthread_key_t tssKey;


static void keyCleanup(void *data)
{
    int i;

    /* Skip or remove TSS data */
    if (!data)
        return;
    else if (pthread_setspecific(tssKey, NULL))
        abort();

    /* Lock cleanup table and call cleanups */
    BH_SpinlockLock(&tssCleanupLock);
    for (i = 0; i < tssCleanupSize; i++)
        tssCleanupData[i](((void **)data)[i]);
    BH_SpinlockUnlock(&tssCleanupLock);

    /* Deallocate TSS data */
    free(data);
}


static void **dataFetch(void)
{
    void **result;

    /* Get or setup TSS data */
    BH_SpinlockLock(&tssLock);
    if (!tssReady)
    {
        if (pthread_key_create(&tssKey, keyCleanup))
            abort();
        tssReady = 1;
    }
    BH_SpinlockUnlock(&tssLock);

    /* Get or setup TSS data */
    result = pthread_getspecific(tssKey);
    if (!result)
    {
        result = malloc(sizeof(void *) * BH_MAX_TSS);
        if (!result)
            abort();

        memset(result, 0, sizeof(void *) * BH_MAX_TSS);
        if (pthread_setspecific(tssKey, result))
            abort();
    }

    return result;
}


void BH_TssCleanup(void)
{
    keyCleanup(dataFetch());
}


int BH_TssCreate(BH_GenericCallback callback)
{
    int result;

    /* Lock info and set up cleanup function */
    BH_SpinlockLock(&tssCleanupLock);
    if (tssCleanupSize < BH_MAX_TSS)
    {
        tssCleanupData[tssCleanupSize] = callback;
        result = tssCleanupSize++;
    }
    else
        result = BH_ERROR;
    BH_SpinlockUnlock(&tssCleanupLock);

    return result;
}


void *BH_TssRead(int index)
{
    return dataFetch()[index];
}


void BH_TssWrite(int index,
                 void *value)
{
    dataFetch()[index] = value;
}