-
Notifications
You must be signed in to change notification settings - Fork 5
/
wat.c
159 lines (112 loc) · 3.14 KB
/
wat.c
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include <string.h>
#include <stdio.h>
#include "erl_nif.h"
#define VAL(data, index) data->data[index].val
#define NELEM(data) data->nelem
typedef struct {
int val;
} PRIVVAL;
typedef struct {
ErlNifMutex *lock;
int nelem;
PRIVVAL *data;
} PRIVDATA;
static ERL_NIF_TERM error_tuple(ErlNifEnv *env, char *err);
static int
load(ErlNifEnv *env, void **priv, ERL_NIF_TERM load_info)
{
PRIVDATA *data = NULL;
int nelem = 0;
if (!enif_get_int(env, load_info, &nelem) || (nelem < 1))
return (-1);
data = (PRIVDATA *)enif_alloc(sizeof(PRIVDATA));
if (data == NULL)
return (-1);
data->data = (PRIVVAL *)enif_alloc(sizeof(PRIVVAL) * nelem);
if (data->data == NULL) {
enif_free(data);
return (-1);
}
(void)memset(data->data, 0, sizeof(PRIVVAL) * nelem);
data->lock = enif_mutex_create("wat_lock");
if (data->lock == NULL)
return (-1);
NELEM(data) = nelem;
*priv = data;
return (0);
}
static int
reload(ErlNifEnv *env, void **priv, ERL_NIF_TERM load_info)
{
enif_mutex_destroy(((PRIVDATA *)*priv)->lock);
enif_free(((PRIVDATA *)*priv)->data);
enif_free(*priv);
return load(env, priv, load_info);
}
static ERL_NIF_TERM
get(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
PRIVDATA *data = NULL;
int k = 0;
int nelem = 0;
data = (PRIVDATA *)enif_priv_data(env);
nelem = NELEM(data);
if (!enif_get_int(env, argv[0], &k))
return enif_make_badarg(env);
if ( (k < 0) || (k >= nelem))
return error_tuple(env, "out_of_bounds");
return enif_make_int(env, VAL(data, k));
}
/* args: 0:key, 1:value */
static ERL_NIF_TERM
set(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
PRIVDATA *data = NULL;
int k = 0;
int v = 0;
int nelem = 0;
data = (PRIVDATA *)enif_priv_data(env);
nelem = NELEM(data);
if ( !enif_get_int(env, argv[0], &k) ||
!enif_get_int(env, argv[1], &v))
return enif_make_badarg(env);
if ( (k < 0) || (k >= nelem))
return error_tuple(env, "out_of_bounds");
enif_mutex_lock(data->lock);
VAL(data, k) = v;
enif_mutex_unlock(data->lock);
return enif_make_int(env, v);
}
static ERL_NIF_TERM
add(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
PRIVDATA *data = NULL;
int k = 0;
int v = 0;
int nelem = 0;
data = (PRIVDATA *)enif_priv_data(env);
nelem = NELEM(data);
if ( !enif_get_int(env, argv[0], &k) ||
!enif_get_int(env, argv[1], &v))
return enif_make_badarg(env);
if ( (k < 0) || (k >= nelem))
return error_tuple(env, "out_of_bounds");
enif_mutex_lock(data->lock);
VAL(data, k) += v;
v = VAL(data, k);
enif_mutex_unlock(data->lock);
return enif_make_int(env, v);
}
static ERL_NIF_TERM
error_tuple(ErlNifEnv *env, char *err)
{
return enif_make_tuple(env, 2,
enif_make_atom(env, "error"),
enif_make_atom(env, err));
}
static ErlNifFunc nif_funcs[] = {
{"get", 1, get},
{"set", 2, set},
{"add", 2, add}
};
ERL_NIF_INIT(wat, nif_funcs, load, reload, NULL, NULL)