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