Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/tests/cdt/tvsaferehash.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1999-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#include "dttest.h"
21
22
#include <vmalloc.h>
23
#include <sys/mman.h>
24
25
/* Test concurrent insert/delete/search by pingpong objects between
26
** two dictionaries, one built with mmap and the other shmget.
27
*/
28
29
#ifndef N_PROC
30
#define N_PROC 64
31
#endif
32
#if N_PROC < 2
33
#undef N_PROC
34
#define N_PROC 2
35
#endif
36
37
#define N_CONCUR ((N_PROC/2)*2) /* #players, must be even */
38
#define N_OBJ 20000 /* total number of objects */
39
#define MEMSIZE (N_OBJ*2*sizeof(Obj_t) + sizeof(Void_t*)*(1<<24) )
40
41
#define DT_DATA 1 /* data section of dictionary */
42
#define DT_PROCESS 2 /* count of started processes */
43
44
/* a persistent object is a pair of string and decimal number */
45
typedef struct obj_s
46
{ Dtlink_t link; /* dictionary holder */
47
int dval; /* decimal value */
48
int accn; /* # of times accessed */
49
} Obj_t;
50
51
/* Cdt discipline to allocate memory from a vmalloc region */
52
typedef struct _mmdisc_s
53
{ Dtdisc_t disc; /* cdt discipline */
54
char* store; /* backing store file name */
55
Vmalloc_t* vm; /* shm vmalloc region */
56
} Mmdisc_t;
57
58
static char *Mapstore;
59
static char *Shmstore;
60
static Mmdisc_t Mapdisc, Shmdisc;
61
62
/* allocate data from the shared memory region */
63
Void_t* mmmemory(Dt_t* dt, Void_t* data, size_t size, Dtdisc_t* disc)
64
{
65
return vmresize(((Mmdisc_t*)disc)->vm, data, size, 0);
66
}
67
68
/* handle dictionary events */
69
static int mmevent(Dt_t* dt, int type, Void_t* data, Dtdisc_t* disc)
70
{
71
Void_t *ctrl;
72
Mmdisc_t *mmdc = (Mmdisc_t*)disc;
73
74
if(type == DT_OPEN)
75
{ ctrl = vmmvalue(mmdc->vm, DT_DATA, (Void_t*)0, VM_MMGET);
76
if(data) /* at the start of a dictionary opening */
77
{ if(!ctrl) /* data area not yet constructed */
78
return 0;
79
else /* got data area, just return it */
80
{ *((Void_t**)data) = ctrl;
81
return 1;
82
}
83
}
84
else return 0;
85
}
86
else if(type == DT_ENDOPEN) /* at the end of a dictionary opening */
87
{ ctrl = vmmvalue(mmdc->vm, DT_DATA, (Void_t*)0, VM_MMGET);
88
if(!ctrl) /* data area just constructed, record it */
89
{ ctrl = vmmvalue(mmdc->vm, DT_DATA, (Void_t*)dt->data, VM_MMSET);
90
return ctrl == (Void_t*)dt->data ? 0 : -1;
91
}
92
else return 0; /* data area existed */
93
}
94
else if(type == DT_CLOSE)
95
return 1; /* make sure no objects get deleted */
96
else if(type == DT_ENDCLOSE) /* at end of closing, close the memory region */
97
{ vmmrelease(mmdc->vm, 0);
98
vmclose(mmdc->vm);
99
mmdc->vm = NIL(Vmalloc_t*);
100
return 0; /* all done */
101
}
102
else return 0;
103
}
104
105
/* compare two objects by their integer keys */
106
static int mmcompare(Dt_t* dt, Void_t* key1, Void_t* key2, Dtdisc_t* disc)
107
{
108
return *((int*)key1) - *((int*)key2);
109
}
110
111
/* open a shared dictionary based on a common backing store */
112
static Dt_t* opendictionary(int num, pid_t pid, char* store)
113
{
114
Vmalloc_t *vm;
115
Dt_t *dt;
116
ssize_t size;
117
int proj;
118
Mmdisc_t *mmdc;
119
120
/* create/reopen the region backed by a file using mmap */
121
proj = store == Mapstore ? -1 : 1;
122
if(!(vm = vmmopen(store, proj, MEMSIZE)) )
123
terror("Process[num=%d,pid=%d]: Couldn't create vmalloc region", num, pid);
124
125
/* discipline for objects identified by their decimal values */
126
mmdc = store == Mapstore ? &Mapdisc : &Shmdisc;
127
mmdc->disc.key = (ssize_t)DTOFFSET(Obj_t,dval);
128
mmdc->disc.size = (ssize_t)sizeof(int);
129
#if 1
130
mmdc->disc.link = (ssize_t)DTOFFSET(Obj_t,link);
131
#else
132
mmdc->disc.link = -1;
133
#endif
134
mmdc->disc.makef = (Dtmake_f)0;
135
mmdc->disc.freef = (Dtfree_f)0;
136
mmdc->disc.comparf = mmcompare;
137
mmdc->disc.hashf = (Dthash_f)0;
138
mmdc->disc.memoryf = mmmemory;
139
mmdc->disc.eventf = mmevent;
140
mmdc->store = store;
141
mmdc->vm = vm;
142
143
if(!(dt = dtopen(&mmdc->disc, Dtrhset)) ) /* open dictionary with hash-trie */
144
terror("Process[num=%d,pid=%d]: Can't open dictionary for %s", num, pid, store);
145
dtcustomize(dt, DT_SHARE, 1); /* turn on concurrent access mode */
146
147
return dt;
148
}
149
150
/* Creating a subprocess */
151
static pid_t makeprocess(char* proc, int num, char* aso)
152
{
153
int i;
154
pid_t pid;
155
char text[16];
156
char *argv[8];
157
158
if((pid = fork()) < 0 )
159
terror("Process[num=%d]: Could not fork() a subprocess", num);
160
else if(pid > 0 ) /* return to parent process */
161
return pid;
162
else
163
{ sprintf(text, "%d", num);
164
i = 0;
165
argv[i++] = proc;
166
if (aso)
167
argv[i++] = aso;
168
argv[i++] = "--child";
169
argv[i++] = Mapstore;
170
argv[i++] = Shmstore;
171
argv[i++] = text;
172
argv[i] = 0;
173
if(execv(proc, argv) < 0 )
174
terror("Process[num=%d]: Could not execv() %s", num, proc);
175
}
176
return -1;
177
}
178
179
/* concurrent read/write hashed objects into a mmap-region */
180
static int pingpong(char* procnum)
181
{
182
int k, p, num, dir, n_move;
183
Obj_t obj, *o;
184
Dt_t *shmdt, *mapdt, *insdt, *deldt;
185
Mmdisc_t *mapdc, *shmdc;
186
pid_t pid;
187
188
num = atoi(procnum);
189
if((pid = getpid()) < 0 )
190
terror("Process[num=%d]: can't get process id", num);
191
192
/* open the shared dictionaries */
193
if(!(mapdt = opendictionary(num, pid, Mapstore)) )
194
terror("Process[num=%d,pid=%d]: can't open dictionary for %s", num, pid, Mapstore);
195
if(!(mapdc = (Mmdisc_t*)dtdisc(mapdt, NIL(Dtdisc_t*), 0)) )
196
terror("Process[num=%d,pid=%d]: can't get dictionary discipline", num, pid);
197
if(!(shmdt = opendictionary(num, pid, Shmstore)) )
198
terror("Process[num=%d,pid=%d]: can't open dictionary for %s", num, pid, Shmstore);
199
if(!(shmdc = (Mmdisc_t*)dtdisc(shmdt, NIL(Dtdisc_t*), 0)) )
200
terror("Process[num=%d,pid=%d]: can't get dictionary discipline", num, pid);
201
202
/* wait for all to get going first */
203
p = (int)((long)vmmvalue(mapdc->vm, DT_PROCESS, (Void_t*)1, VM_MMADD));
204
for(k = 0; p < N_CONCUR; asorelax(1<<k), k = (k+1)&07 ) /* wait until all inserters are running */
205
p = (int)((long)vmmvalue(mapdc->vm, DT_PROCESS, (Void_t*)0, VM_MMGET));
206
tinfo("Process[num=%d,pid=%d]: ready to go", num, pid);
207
208
/* delete from one and insert to the other */
209
deldt = num%2 == 0 ? mapdt : shmdt;
210
insdt = num%2 == 0 ? shmdt : mapdt;
211
n_move = 0;
212
for(dir = 1; dir >= -1; dir -= 2)
213
{ for(k = dir > 0 ? 0 : N_OBJ-1; k >= 0 && k < N_OBJ; k += dir)
214
{ obj.dval = k;
215
if((o = dtsearch(deldt, &obj)) && (random()%2) == 0 && dtdelete(deldt, o) == o )
216
{ dtinsert(insdt, o);
217
n_move += 1;
218
}
219
}
220
}
221
tinfo("Process[num=%d,pid=%d]: move %d (%s -> %s)",
222
num, pid, n_move, num%2 == 0 ? "map" : "shm", num%2 == 0 ? "shm" : "map");
223
224
dtclose(mapdt);
225
dtclose(shmdt);
226
227
return 0;
228
}
229
230
tmain()
231
{
232
pid_t cpid[N_CONCUR], ppid, pid;
233
size_t i, k, p;
234
char *aso;
235
Dt_t *mapdt, *shmdt;
236
Mmdisc_t *mapdc, *shmdc;
237
Obj_t *os, *om, obj;
238
239
aso = taso(ASO_PROCESS);
240
if(k = tchild())
241
{ Mapstore = argv[k++];
242
Shmstore = argv[k++];
243
return pingpong(argv[k]);
244
}
245
if((ppid = getpid()) < 0 )
246
terror("Parent: can't get process id");
247
Mapstore = tstfile("map", -1);
248
Shmstore = tstfile("shm", -1);
249
(void)unlink(Mapstore);
250
(void)unlink(Shmstore);
251
252
tinfo("\tParent[pid=%d]: initializing shared dictionaries", ppid);
253
if(!(mapdt = opendictionary(0, ppid, Mapstore)) )
254
terror("Parent[pid=%d]: Can't open dictionary for %s", ppid, Mapstore);
255
if(!(mapdc = (Mmdisc_t*)dtdisc(mapdt, NIL(Dtdisc_t*), 0)) )
256
terror("Parent[pid=%d]: Can't get discipline for %s", ppid, Mapstore);
257
vmmrelease(mapdc->vm, 1); /* to remove file on parent exit */
258
259
if(!(shmdt = opendictionary(0, ppid, Shmstore)) )
260
terror("Parent[pid=%d]: Can't open dictionary for %s", ppid, Shmstore);
261
if(!(shmdc = (Mmdisc_t*)dtdisc(shmdt, NIL(Dtdisc_t*), 0)) )
262
terror("Parent[pid=%d]: Can't get discipline for %s", ppid, Shmstore);
263
vmmrelease(shmdc->vm, 1); /* to remove shmid on parent exit */
264
265
for(k = 0; k < N_OBJ; ++k)
266
{ if(random()%2 == 0)
267
{ if(!(om = vmalloc(mapdc->vm, sizeof(Obj_t))) )
268
terror("Parent[pid=%d]: vmalloc failed k=%d store=%s", ppid, k, Mapstore);
269
om->dval = k;
270
if(dtinsert(mapdt, om) != om)
271
terror("Parent[pid=%d]: dtinsert failed k=%d store=%s", ppid, k, Mapstore);
272
}
273
else
274
{ if(!(os = vmalloc(shmdc->vm, sizeof(Obj_t))) )
275
terror("Parent[pid=%d]: vmalloc failed k=%d store=%s", ppid, k, Shmstore);
276
os->dval = k;
277
if(dtinsert(shmdt, os) != os)
278
terror("Parent[pid=%d]: dtinsert failed k=%d store=%s", ppid, k, Shmstore);
279
}
280
}
281
282
tinfo("\tParent[pid=%d]: creating pingpong subprocesses", ppid);
283
for(p = 0; p < N_CONCUR; ++p )
284
if((cpid[p] = makeprocess(argv[0], p, aso)) < 0 )
285
terror("Parent[pid=%d]: Could not make process %d", ppid, p);
286
if (twait(cpid, N_CONCUR))
287
terror("workload subprocess error");
288
289
tinfo("\tParent[pid=%d]: check integrity", ppid);
290
291
k = dtsize(mapdt);
292
p = dtsize(shmdt);
293
tinfo("Parent[pid=%d]: mapdt=%d shmdt=%d", ppid, k, p);
294
if((k+p) != N_OBJ)
295
terror("Parent[pid=%d]: expecting %d objects but (mapdt+shmdt)=%d", ppid, N_OBJ, k+p);
296
297
for(k = 0; k < N_OBJ; ++k)
298
{ Obj_t obj, *om, *os;
299
300
obj.dval = k;
301
om = dtsearch(mapdt, &obj);
302
os = dtsearch(shmdt, &obj);
303
if(om && os)
304
terror("Parent[pid=%d]: object %d is in both dictionaries", ppid, k);
305
if(!om && !os)
306
terror("Parent[pid=%d]: object %d is in neither dictionary", ppid, k);
307
}
308
309
/* clean up file/shmid data */
310
dtclose(mapdt);
311
dtclose(shmdt);
312
313
texit(0);
314
}
315
316