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