Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/tests/cdt/tvsharemem.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
#include <sys/time.h>
25
26
/* Test insert/delete/search in shared/persistent memory region. */
27
28
#ifndef N_PROC
29
#define N_PROC 48
30
#endif
31
#if N_PROC < 8
32
#undef N_PROC
33
#define N_PROC 8
34
#endif
35
36
#define N_INSERT (N_PROC/3) /* #concurrent writers */
37
#define N_DELETE (N_PROC/3) /* #concurrent deleters */
38
#define N_SEARCH (N_PROC/3) /* #concurrent searchers */
39
#define N_WRITER (N_INSERT+N_DELETE)
40
#define N_PROCESS (N_INSERT+N_DELETE+N_SEARCH)
41
#define W_EXTENT (2604*N_PROCESS)/* size of a dataset to write */
42
#define COLLISION (N_INSERT/2) /* should be < N_INSERT */
43
44
#define DTMETHOD Dtrhset /* storage method to use */
45
#define LONGGONE (-1000000) /* setting refn to gone */
46
47
static int Count[N_INSERT*W_EXTENT];
48
49
static char *Mapstore, *Shmstore;
50
51
#define MEMSIZE (4*N_INSERT*W_EXTENT*(sizeof(Obj_t)+16) + 64*1024*1024)
52
53
#define CDT_DATA 1 /* data section of dictionary */
54
#define CDT_WRITER 2 /* count of started inserters */
55
#define CDT_SEARCHER 3 /* count of started searchers */
56
#define CDT_FINISHED 4 /* count of done process */
57
#define CDT_INSERT 5 /* #inserts across processes */
58
#define CDT_DELETE 6 /* #inserts across processes */
59
#define CDT_INCOMPLETE 7 /* #incomplete objects */
60
61
/* a persistent object is a pair of string and decimal number */
62
typedef struct obj_s
63
{ Dtlink_t link; /* dictionary holder */
64
int dval; /* decimal value */
65
char* sval; /* corrresponding string value */
66
int ready; /* object ready to be used */
67
int refn; /* usage reference count */
68
69
/* below are extra data good to help debugging */
70
int type; /* last announced op */
71
int opid; /* pid of that op */
72
int ins; /* #seen by an insert process */
73
int del; /* #seen by a delete process */
74
int srch; /* #seen by a search process */
75
int free; /* #of times being freed */
76
int fpid; /* process that freed it */
77
struct obj_s* next; /* link for free list */
78
} Obj_t;
79
80
/* Cdt discipline to allocate memory from a vmalloc region */
81
typedef struct _mmdisc_s
82
{ Dtdisc_t disc; /* cdt discipline */
83
Vmalloc_t* vm; /* vmalloc region */
84
ssize_t ndel; /* delete count */
85
Obj_t* list; /* free list */
86
int pid;
87
} Mmdisc_t;
88
89
/* allocate data from the shared memory region */
90
Void_t* mmmemory(Dt_t* dt, Void_t* data, size_t size, Dtdisc_t* disc)
91
{
92
return vmresize(((Mmdisc_t*)disc)->vm, data, size, 0);
93
}
94
95
/* handle dictionary events */
96
static int mmevent(Dt_t* dt, int type, Void_t* data, Dtdisc_t* disc)
97
{
98
Void_t *ctrl;
99
Mmdisc_t *mmdc = (Mmdisc_t*)disc;
100
101
if(type == DT_OPEN)
102
{ ctrl = vmmvalue(mmdc->vm, CDT_DATA, (Void_t*)0, VM_MMGET);
103
if(data) /* at the start of a dictionary opening */
104
{ if(!ctrl) /* data area not yet constructed */
105
return 0;
106
else /* got data area, just return it */
107
{ *((Void_t**)data) = ctrl;
108
return 1;
109
}
110
}
111
else return 0;
112
}
113
else if(type == DT_ENDOPEN) /* at the end of a dictionary opening */
114
{ ctrl = vmmvalue(mmdc->vm, CDT_DATA, (Void_t*)0, VM_MMGET);
115
if(!ctrl) /* data area just constructed, record it */
116
{ ctrl = vmmvalue(mmdc->vm, CDT_DATA, (Void_t*)dt->data, VM_MMSET);
117
return ctrl == (Void_t*)dt->data ? 0 : -1;
118
}
119
else return 0; /* data area existed */
120
}
121
else if(type == DT_CLOSE)
122
return 1; /* make sure no objects get deleted */
123
else if(type == DT_ENDCLOSE) /* at end of closing, close the memory region */
124
{ vmmrelease(mmdc->vm, 0);
125
vmclose(mmdc->vm);
126
mmdc->vm = NIL(Vmalloc_t*);
127
return 0; /* all done */
128
}
129
else if(type & DT_ANNOUNCE)
130
{ Obj_t *obj = (Obj_t*)data;
131
132
if(obj->refn < 0 ) /* must be the last announcement from dtdelete() */
133
{ if(obj->refn != LONGGONE)
134
terror("Process %d: refn != LONGGONE op=%d obj[%d,refn=%d,fpid=%d]",
135
mmdc->pid, type&~DT_ANNOUNCE, obj->dval, obj->refn, obj->fpid);
136
if(!(type&DT_DELETE) )
137
tpause("Process %d: Op=%d != DT_DELETE obj[%d,refn=%d,fpid=%d]",
138
mmdc->pid, type&~DT_ANNOUNCE, obj->dval, obj->refn, obj->fpid);
139
}
140
141
obj->type = type & ~DT_ANNOUNCE; /* record the announcement */
142
obj->opid = mmdc->pid;
143
144
if(!(type & DT_DELETE) ) /* test this because obj may be gone */
145
{ /* Wait-loop for object completion. The below "if"
146
** statement causes the loop to be executed in all
147
** cases except for the dtinsert()/dtattach() that
148
** will complete constructing the object.
149
*/
150
if(type & ~(DT_ANNOUNCE|DT_INSERT|DT_ATTACH) )
151
while(obj->ready == 0 )
152
asorelax(1);
153
154
/* increase reference count */
155
if(asoincint(&obj->refn) < 0 )
156
tpause("Process %d: refn<0 on adding op=%d obj[%d,refn=%d,fpid=%d]",
157
mmdc->pid, type&~DT_ANNOUNCE, obj->dval, obj->refn, obj->fpid);
158
}
159
160
return 0;
161
}
162
else return 0;
163
}
164
165
/* compare two objects by their integer keys */
166
static int mmcompare(Dt_t* dt, Void_t* key1, Void_t* key2, Dtdisc_t* disc)
167
{
168
return *((int*)key1) - *((int*)key2);
169
}
170
171
/* free a deleted object */
172
static void mmfree(Dt_t* dt, Void_t* objarg, Dtdisc_t* disc)
173
{
174
int refn;
175
Obj_t *obj = (Obj_t*)objarg;
176
Mmdisc_t *mmdc = (Mmdisc_t*)dt->disc;
177
178
if(obj->free > 0 ) /* already freed, not good! */
179
terror("Process %d: multiple deletion? obj[%d,sval=%s,free=%d,pid=%d,refn=%d]",
180
mmdc->pid, obj->dval, obj->sval, obj->free, obj->fpid, obj->refn );
181
182
while(!obj->ready) /* object must be complete before deletable */
183
asorelax(1);
184
185
obj->fpid = mmdc->pid; /* process doing deletion */
186
obj->free += 1; /* set indicator that it's free */
187
188
while(obj->refn > 0) /* wait until no further reference to it */
189
asorelax(1);
190
191
/* set reference number to LONGGONE */
192
if((refn = (int)asocasint(&obj->refn, 0, (uint)LONGGONE)) != 0 )
193
terror("Process %d: refn=%d > 0? obj[%d,sval=%s,free=%d,pid=%d,refn=%d,op=%d]",
194
mmdc->pid, refn, obj->dval, obj->sval, obj->free, obj->fpid, obj->refn, obj->type );
195
196
obj->dval = -obj->dval; /* deleted objects have negative id */
197
obj->next = mmdc->list; /* add to free list, this could be a garbage-collector */
198
mmdc->list = obj;
199
mmdc->ndel += 1;
200
}
201
202
/* open a shared dictionary based on a common backing store */
203
static Dt_t* opendictionary(char* actor, char* type, int num, pid_t pid, char* store)
204
{
205
Vmalloc_t *vm;
206
Dt_t *dt;
207
ssize_t size;
208
static Mmdisc_t Mmdc; /* CDT discipline for shared dictionary */
209
210
/* create/reopen the region backed by a file using mmap */
211
if(!(vm = vmmopen(store, store == Mapstore ? -1 : 1, MEMSIZE)) )
212
terror("%s %s [num=%d,pid=%d]: Couldn't create vmalloc region", actor, type, num, pid);
213
214
/* discipline for objects identified by their decimal values */
215
Mmdc.disc.key = (ssize_t)DTOFFSET(Obj_t,dval);
216
Mmdc.disc.size = (ssize_t)sizeof(int);
217
Mmdc.disc.link = (ssize_t)DTOFFSET(Obj_t,link);
218
Mmdc.disc.makef = (Dtmake_f)0;
219
Mmdc.disc.freef = mmfree;
220
Mmdc.disc.comparf = mmcompare;
221
Mmdc.disc.hashf = (Dthash_f)0;
222
Mmdc.disc.memoryf = mmmemory;
223
Mmdc.disc.eventf = mmevent;
224
Mmdc.vm = vm;
225
Mmdc.ndel = 0;
226
Mmdc.list = (Obj_t*)0;
227
Mmdc.pid = (int)getpid();
228
229
if(!(dt = dtopen(&Mmdc.disc, DTMETHOD)) ) /* open dictionary with hash-trie */
230
terror("%s %s [num=%d,pid=%d]: Can't open dictionary", actor, type, num, pid);
231
if(dtcustomize(dt, (DT_ANNOUNCE|DT_SHARE), 1) != (DT_ANNOUNCE|DT_SHARE) )
232
terror("%s %s [num=%d,pid=%d]: Can't customize dictionary", actor, type, num, pid);
233
234
return dt;
235
}
236
237
/* Creating a subprocess to write/read a dictionary */
238
static pid_t makeprocess(char* proc, char* type, char* actor, int num, char* aso)
239
{
240
int i;
241
pid_t pid;
242
char text[16];
243
char *argv[9];
244
245
if((pid = fork()) < 0 )
246
terror("%s %s [num=%d]: Could not fork() a subprocess", actor, type, num);
247
else if(pid > 0 ) /* return to parent process */
248
return pid;
249
else
250
{ sprintf(text, "%d", num);
251
i = 0;
252
argv[i++] = proc;
253
if (aso)
254
argv[i++] = aso;
255
argv[i++] = "--child";
256
argv[i++] = Mapstore;
257
argv[i++] = Shmstore;
258
argv[i++] = type;
259
argv[i++] = actor;
260
argv[i++] = text;
261
argv[i++] = 0;
262
if(execv(proc, argv) < 0 )
263
terror("%s %s [num=%d]: Could not execv() process %s %s", actor, type, num, proc, type);
264
}
265
return -1;
266
}
267
268
/* concurrent read/write hashed objects into a mmap-region */
269
static int readwrite(char* type, char* store, char* actor, char* procnum)
270
{
271
int i, k, p, num, base, insert, delete, search, unsrch, undel, unins, walk, first, size;
272
char *sval;
273
Obj_t obj, *o, *next, *rv;
274
Dt_t *dt;
275
pid_t pid;
276
Mmdisc_t *mmdc;
277
278
num = atoi(procnum);
279
if((pid = getpid()) < 0 )
280
terror("%s %s [num=%d]: can't get process id", actor, type, num);
281
282
/* open the shared/persistent dictionary */
283
if(!(dt = opendictionary(actor, type, num, pid, store)) )
284
terror("%s %s [num=%d,pid=%d]: can't open dictionary", actor, type, num, pid);
285
286
/* get the discipline structure with the Vmalloc region */
287
if(!(mmdc = (Mmdisc_t*)dtdisc(dt, NIL(Dtdisc_t*), 0)) )
288
terror("%s %s [num=%d,pid=%d]: can't get dictionary discipline", actor, type, num, pid);
289
290
/* all writers wait until they are all ready before going */
291
if(strcmp(actor, "inserter") == 0 || strcmp(actor, "deleter") == 0)
292
{ p = (int)((long)vmmvalue(mmdc->vm, CDT_WRITER, (Void_t*)1, VM_MMADD));
293
for(; p < N_WRITER; asorelax(1) ) /* wait until all writers are running */
294
p = (int)((long)vmmvalue(mmdc->vm, CDT_WRITER, (Void_t*)0, VM_MMGET));
295
}
296
else /* searchers wait for everyone to be ready before going */
297
{ p = (int)((long)vmmvalue(mmdc->vm, CDT_SEARCHER, (Void_t*)1, VM_MMADD));
298
k = (int)((long)vmmvalue(mmdc->vm, CDT_WRITER, (Void_t*)0, VM_MMGET));
299
for(; p+k < N_PROCESS; asorelax(1) ) /* wait until all are running */
300
{ p = (int)((long)vmmvalue(mmdc->vm, CDT_SEARCHER, (Void_t*)0, VM_MMGET));
301
k = (int)((long)vmmvalue(mmdc->vm, CDT_WRITER, (Void_t*)0, VM_MMGET));
302
}
303
}
304
305
#define BASE(n) ((n)*W_EXTENT + 1) /* base number of objects to be inserted */
306
walk = first = insert = delete = search = unsrch = unins = undel = 0;
307
if(strcmp(actor, "inserter") == 0 )
308
{ base = BASE((num/COLLISION)*COLLISION); /* make these inserters do the same thing */
309
tinfo("%s %s [num=%d,pid=%d]: range=[%d,%d) ready to go", actor, type, num, pid, base, base+W_EXTENT);
310
311
for(i = 0; i < W_EXTENT; ++i)
312
{ /* insert a new object */
313
if(!(o = (Obj_t*)vmalloc(mmdc->vm, sizeof(Obj_t))) )
314
terror("%s %s [num=%d,pid=%d]: vmalloc failed", actor, type, num, pid);
315
316
memset(o, 0, sizeof(Obj_t));
317
o->dval = i+base;
318
if(!(rv = dtinsert(dt, o)) ) /* failed insert */
319
terror("%s %s [num=%d,pid=%d]: insert failed", actor, type, num, pid);
320
321
if(rv == o) /* successfully inserted, complete it by making string value */
322
{ insert += 1;
323
324
if(!(sval = vmalloc(mmdc->vm, 16)) ) /* construct string value */
325
terror("%s %s [num=%d,pid=%d]: vmalloc failed", actor, type, num, pid);
326
sprintf(sval, "%d", o->dval);
327
o->sval = sval;
328
329
if(o->dval < 0) /* this ain't no way! */
330
terror("%s %s [num=%d,pid=%d]: already freed? obj[dval=%d,pid=%d]",
331
actor, type, num, pid, o->dval, o->fpid);
332
333
if(o->refn != 1 ) /* everyone else should still be spinning */
334
terror("%s %s [num=%d,pid=%d]: refn != 1? obj[dval=%d,refn=%d,op=%d,opid=%d]",
335
actor, type, num, pid, o->dval, o->refn, o->type, o->opid);
336
337
o->ready = 1; /* tell the world that object is ready */
338
asodecint(&o->refn); /* decrease o's reference count */
339
}
340
else
341
{ unins += 1; /* already been constructed by someone else */
342
vmfree(mmdc->vm, o);
343
344
if(rv->refn <= 0 || rv->dval < 0) /* refn should be at least 1 */
345
terror("%s %s [num=%d,pid=%d]: refn <= 0? obj[dval=%d,refn=%d,op=%d,opid=%d]",
346
actor, type, num, pid, o->dval, o->refn, o->type, o->opid);
347
348
if(!rv->sval) /* count #incomplete objects */
349
vmmvalue(mmdc->vm, CDT_INCOMPLETE, (Void_t*)1, VM_MMADD);
350
351
asodecint(&rv->refn); /* decrease rv's reference count */
352
}
353
}
354
355
tinfo("%s %s [num=%d,pid=%d]: done, base=%d try=%d insert=%d[+%d]",
356
actor, type, num, pid, base, W_EXTENT, insert, unins);
357
358
/* total number of successful inserts */
359
vmmvalue(mmdc->vm, CDT_INSERT, (Void_t*)((long)insert), VM_MMADD );
360
}
361
else if(strcmp(actor, "deleter") == 0 )
362
{ srandom(num);
363
size = dtsize(dt);
364
tinfo("%s %s [num=%d,pid=%d]: dtsize=%d ready to go", actor, type, num, pid, size);
365
366
for(o = dtfirst(dt); o; o = next )
367
{ next = dtnext(dt,o);
368
walk += 1;
369
370
if(o->refn <= 0 ) /* refn should be >= 1 */
371
terror("%s %s [num=%d,pid=%d]: refn <= 0? obj[dval=%d,refn=%d,op=%d,opid=%d]",
372
actor, type, num, pid, o->dval, o->refn, o->type, o->opid);
373
374
if(!o->sval) /* count incomplete objects */
375
vmmvalue(mmdc->vm, CDT_INCOMPLETE, (Void_t*)1, VM_MMADD);
376
377
asodecint(&o->refn);
378
379
if(!(rv = dtdelete(dt,o)) )
380
undel += 1; /* somebody beat us to it */
381
else delete += 1;
382
}
383
384
tinfo("%s %s [num=%d,pid=%d]: done, size=%d[walk=%d] delete=%d[+%d]",
385
actor, type, num, pid, size, walk, delete, undel);
386
387
size = 0; /* make sure that free elements were deleted right */
388
for(o = mmdc->list; o; o = next)
389
{ next = o->next;
390
size += 1;
391
if(o->free != 1) /* multiply deleted? */
392
terror("%s %s [num=%d,pid=%d]: multiple delete? obj[dval=%d,free=%d,fpid=%d]",
393
actor, type, num, mmdc->pid, o->dval, o->free, o->fpid);
394
if(o->fpid != mmdc->pid) /* who deleted this? */
395
terror("%s %s [num=%d,pid=%d]: Wrong deleter obj[dval=%d,free=%d,fpid=%d]",
396
actor, type, num, mmdc->pid, o->dval, o->free, o->fpid);
397
}
398
if(size != delete)
399
terror("%s %s [num=%d,pid=%d]: free=%d delete=%d", actor, type, num, pid, size, delete);
400
401
/* save the number of deleted objects */
402
vmmvalue(mmdc->vm, CDT_DELETE, (Void_t*)((long)delete), VM_MMADD );
403
}
404
else if(strcmp(actor, "searcher") == 0 )
405
{ srandom(num);
406
size = dtsize(dt);
407
tinfo("%s %s [num=%d,pid=%d]: dtsize=%d ready to go", actor, type, num, pid, size);
408
409
size = size > COLLISION*W_EXTENT ? size : COLLISION*W_EXTENT;
410
if(num%2 == 0 ) /* this searcher searches random elements */
411
{ for(k = 0; k < size; ++k)
412
{ obj.dval = random()%(N_INSERT*W_EXTENT) + 1;
413
if(!(rv = dtsearch(dt, &obj)) )
414
unsrch += 1;
415
else
416
{ search += 1;
417
418
if(rv->dval < 0) /* should not be freed yet */
419
terror("%s %s [num=%d,pid=%d]: already freed? obj[%d,fpid=%d]",
420
actor, type, num, pid, rv->dval, rv->fpid);
421
422
if(rv->refn <= 0) /* refn should be at least 1 just for us */
423
terror("%s %s [num=%d,pid=%d]: refn <= 0? obj[%d,refn=%d,op=%d,opid=%d]",
424
actor, type, num, pid, rv->dval, rv->refn, rv->type, rv->opid);
425
426
if(!rv->sval) /* count incomplete objects */
427
vmmvalue(mmdc->vm, CDT_INCOMPLETE, (Void_t*)1, VM_MMADD);
428
429
asodecint(&rv->refn);
430
}
431
}
432
size = dtsize(dt);
433
tinfo("%s %s [num=%d,pid=%d]: done, dtsize=%d search=%d[+%d]",
434
actor, type, num, pid, size, search, unsrch);
435
}
436
else /* this searcher walks the dictionary */
437
{ obj.dval = 0;
438
for(k = 0; k < size; ++k)
439
{ if((o = dtnext(dt, &obj)) )
440
walk += 1;
441
else if((o = dtfirst(dt)) )
442
first += 1;
443
else break; /* empty dictionary */
444
445
if(o->dval < 0) /* should not be deleted yet */
446
terror("%s %s [num=%d,pid=%d]: already freed obj[%d,refn=%d,fpid=%d,op=%d,opid=%d ",
447
actor, type, num, pid, o->dval, o->refn, o->fpid, o->type, o->opid);
448
if(o->refn <= 0 ) /* refn must be >= 1 */
449
terror("%s %s [num=%d,pid=%d]: refn<=0? obj[%d,refn=%d,op=%d,opid=%d",
450
actor, type, num, pid, o->dval, o->refn, o->type, o->opid);
451
452
if(!o->sval) /* count incomplete objects */
453
vmmvalue(mmdc->vm, CDT_INCOMPLETE, (Void_t*)1, VM_MMADD);
454
455
obj.dval = o->dval; /* for next search */
456
asodecint(&o->refn); /* reduce reference count */
457
}
458
size = dtsize(dt);
459
tinfo("%s %s [num=%d,pid=%d]: done, dtsize=%d walk=%d first=%d",
460
actor, type, num, pid, size, walk, first);
461
}
462
}
463
else terror("%s %s [num=%d,pid=%d]: unknown actor", actor, num, pid);
464
465
vmmvalue(mmdc->vm, CDT_FINISHED, (Void_t*)1, VM_MMADD); /* count a done process */
466
467
for(p = 0; p < N_PROCESS; asorelax(1) ) /* wait until everyone is done */
468
p = (int)((long)vmmvalue(mmdc->vm, CDT_FINISHED, (Void_t*)0, VM_MMGET));
469
470
insert = (ssize_t)(unsigned long)vmmvalue(mmdc->vm, CDT_INSERT, 0, VM_MMGET);
471
delete = (ssize_t)(unsigned long)vmmvalue(mmdc->vm, CDT_DELETE, 0, VM_MMGET);
472
473
size = dtsize(dt);
474
for(walk = 0, o = dtfirst(dt); o; o = dtnext(dt,o) )
475
walk += 1;
476
tinfo("%s %s [num=%d,pid=%d]: start walk, dtsize=%d, dtfirst/next=%d ins-del=%d",
477
actor, type, num, pid, size, walk, insert-delete);
478
if(insert < delete)
479
terror("%s %s [num=%d,pid=%d]: insert=%d < delete=%d", actor, type, num, pid, insert, delete);
480
if(walk != size)
481
terror("%s %s [num=%d,pid=%d]: dtsize=%d != walk=%d", actor, type, num, pid, size, walk);
482
483
/* concurrently walk the dictionary and add count to appropriate fields */
484
i = strcmp(actor, "inserter") == 0 ? 1 : strcmp(actor, "deleter") == 0 ? 2 : 3;
485
for(k = 0, o = (Obj_t*)dtfirst(dt); o; ++k, o = (Obj_t*)dtnext(dt,o) )
486
{ if(o->dval < 0)
487
terror("%s %s [num=%d,pid=%d]: object %d already freed",
488
actor, type, num, pid, o->dval);
489
490
if(i == 1) /* inserter */
491
{ asoincint(&o->ins);
492
#ifdef DEBUG
493
tlog(pid, "%d", o->dval);
494
#endif
495
}
496
else if(i == 2) /* deleter */
497
{ asoincint(&o->del);
498
#ifdef DEBUG
499
tlog(pid, "%d", o->dval);
500
#endif
501
}
502
else
503
{ asoincint(&o->srch); /* searcher process */
504
#ifdef DEBUG
505
tlog(pid, "%d", o->dval);
506
#endif
507
}
508
}
509
510
/* close dictionary and shared/persistent region */
511
dtclose(dt);
512
513
return 0;
514
}
515
516
tmain()
517
{
518
pid_t wpid[N_INSERT+N_DELETE+N_SEARCH], ppid, pid;
519
size_t size, walk, i, k, p;
520
int t;
521
struct timeval begtm, endtm;
522
Dt_t *dt;
523
Obj_t *o;
524
Mmdisc_t *mmdc;
525
Vmalloc_t *vm;
526
char *aso, *a, *cmd, *store, *type;
527
528
cmd = *argv;
529
aso = taso(ASO_PROCESS);
530
if(k = tchild())
531
{ Mapstore = argv[k++];
532
Shmstore = argv[k++];
533
type = argv[k++];
534
if(strcmp(type, "map") == 0 )
535
store = Mapstore;
536
else if(strcmp(type, "shm") == 0)
537
store = Shmstore;
538
else
539
terror("%s: invalid store type -- { map shm } expected", type);
540
a = argv[k++];
541
if(strcmp(a, "inserter") == 0 ||
542
strcmp(a, "deleter") == 0 ||
543
strcmp(a, "searcher") == 0 )
544
return readwrite(type, store, a, argv[k]);
545
terror("%s: invalid child process operation -- { inserter deleter searcher } expected", a);
546
}
547
else if(*++argv)
548
t = -1;
549
else
550
t = 0;
551
if((ppid = getpid()) < 0 )
552
terror("Parent: can't get process id");
553
Mapstore = tstfile("map", -1);
554
Shmstore = tstfile("shm", -1);
555
(void)unlink(Mapstore);
556
(void)unlink(Shmstore);
557
558
for(; t < 2; t++)
559
{ switch (t)
560
{
561
case -1:
562
type = *argv++;
563
if(strcmp(type, "map") == 0 )
564
store = Mapstore;
565
else if(strcmp(type, "shm") == 0)
566
store = Shmstore;
567
else
568
terror("%s: invalid store type -- { map shm } expected", type);
569
t = *argv ? -2 : 2;
570
break;
571
case 0:
572
type = "map";
573
store = Mapstore;
574
#if __sun
575
twarn("Skipping %s test on __sun because high mmap() memory sync frequency makes it crawl", type);
576
continue;
577
#else
578
break;
579
#endif
580
case 1:
581
type = "shm";
582
store = Shmstore;
583
break;
584
}
585
586
tinfo("parent %s [pid=%d]: Testing %s concurrent accesses", type, ppid, type);
587
gettimeofday(&begtm, 0);
588
589
tinfo("parent %s [pid=%d]: initializing dictionary", type, ppid);
590
if(!(dt = opendictionary("parent", type, 0, ppid, store)) )
591
terror("parent %s [pid=%d]: Can't open %s dictionary", type, ppid, type);
592
if(!(mmdc = (Mmdisc_t*)dtdisc(dt, (Dtdisc_t*)0, 0)) )
593
terror("parent %s [pid=%d]: Can't get dictionary discipline", type, ppid);
594
tinfo("parent %s [pid=%d]: share dictionary created", type, ppid);
595
596
for(p = i = 0; i < N_INSERT; ++i) /* start inserters */
597
if((wpid[p++] = makeprocess(cmd, type, "inserter", i, aso)) < 0 )
598
terror("parent %s [pid=%d]: Could not make inserter process %d", type, ppid, i);
599
600
for(i = 0; i < N_DELETE; ++i) /* start deleters */
601
if((wpid[p++] = makeprocess(cmd, type, "deleter", i, aso)) < 0 )
602
terror("parent %s [pid=%d]: Could not make deleter process %d", type, ppid, i);
603
604
for(i = 0; i < N_SEARCH; ++i) /* start searchers */
605
if((wpid[p++] = makeprocess(cmd, type, "searcher", i, aso)) < 0 )
606
terror("parent %s [pid=%d]: Could not make searcher process %d", type, ppid, i);
607
608
if (twait(wpid, p))
609
terror("workload subprocess error");
610
611
walk = 0; /* count objects from "persistent" dictionary itself */
612
for(o = (Obj_t*)dtfirst(dt); o; o = (Obj_t*)dtnext(dt,o) )
613
{ if(o->dval < 0 || o->dval > N_INSERT*W_EXTENT)
614
terror("parent %s [pid=%d]: bad object", type, ppid);
615
if(o->ins != N_INSERT)
616
terror("parent %s [pid=%d]: object %d has wrong insert count %d",
617
type, ppid, o->dval, o->ins);
618
if(o->srch != N_SEARCH)
619
terror("parent %s [pid=%d]: object %d has wrong search count %d",
620
type, ppid, o->dval, o->srch);
621
if(o->del != N_DELETE)
622
terror("parent %s [pid=%d]: object %d has wrong delete count %d",
623
type, ppid, o->dval, o->del);
624
#ifdef DEBUG
625
tlog(ppid, "%d", o->dval);
626
#endif
627
628
Count[o->dval] += 1;
629
walk += 1;
630
}
631
632
for(k = 0; k < N_INSERT*W_EXTENT; ++k)
633
if(Count[k] > 1) /* should be unique */
634
terror("parent %s [pid=%d]: Count[%d] = %d > 1", type, ppid, k, Count[k]);
635
636
size = (ssize_t)dtsize(dt);
637
i = (ssize_t)(unsigned long)vmmvalue(mmdc->vm, CDT_INCOMPLETE, (Void_t*)0, VM_MMGET);
638
tinfo("parent %s [pid=%d]: dtfirst/dtnext=%d dtsize=%d, incomplete=%d, no error.",
639
type, ppid, walk, size, i);
640
if(size != walk)
641
terror("parent %s [pid=%d]: counts mismatched", type, ppid);
642
643
tinfo("Storage type=%s, #insertions=%d #inserters=%d #deleters=%d #searchers=%d",
644
type, N_INSERT*W_EXTENT, N_INSERT, N_DELETE, N_SEARCH);
645
646
gettimeofday(&endtm, 0);
647
if(begtm.tv_usec > endtm.tv_usec)
648
{ endtm.tv_sec -= 1;
649
endtm.tv_usec += 1000000;
650
}
651
tinfo("Storage method %s: running time = %ld.%lds",
652
DTMETHOD->name, endtm.tv_sec - begtm.tv_sec, endtm.tv_usec - begtm.tv_usec);
653
654
vmmrelease(mmdc->vm, 1); /* clean up file/shmid data */
655
dtclose(dt);
656
}
657
658
texit(0);
659
}
660
661