2 * Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
3 * Huschaam Hussain <Huschaam.Hussain@hp.com>
4 * TSG Solution Alliances Engineering
7 * Copyright (C) 2015 Karel Zak <kzak@redhat.com>
10 * The test heavily uses shared memory, to enlarge maximal size of shared
13 * echo "4294967295" > /proc/sys/kernel/shmm
15 * The test is compiled against in-tree libuuid, if you want to test uuidd
16 * installed to the system then make sure that libuuid uses the same socket
17 * like the running uuidd. You can start the uuidd manually, for example:
19 * uuidd --debug --no-fork --no-pid --socket /run/uuidd/request
21 * if the $runstatedir (as defined by build-system) is /run. If you want
22 * to overwrite the built-in default then use:
24 * make uuidd uuidgen runstatedir=/var/run
32 #include <sys/types.h>
41 #define LOG(level,args) if (loglev >= level) { fprintf args; }
43 static size_t nprocesses
= 4;
44 static size_t nthreads
= 4;
45 static size_t nobjects
= 4096;
46 static size_t loglev
= 1;
52 typedef struct processentry process_t
;
56 pthread_t tid
; /* pthread_self() / phtread_create() */
57 pthread_attr_t thread_attr
;
58 size_t index
; /* index in object[] */
59 int retval
; /* pthread exit() */
61 typedef struct threadentry thread_t
;
63 /* this is in shared memory, keep it as small as possible */
70 typedef struct objectentry object_t
;
73 static object_t
*objects
;
76 static void __attribute__((__noreturn__
)) usage(void)
78 printf("\n %s [options]\n", program_invocation_short_name
);
80 printf(" -p <num> number of nprocesses (default:%zu)\n", nprocesses
);
81 printf(" -t <num> number of nthreads (default:%zu)\n", nthreads
);
82 printf(" -o <num> number of nobjects (default:%zu)\n", nobjects
);
83 printf(" -l <level> log level (default:%zu)\n", loglev
);
84 printf(" -h display help\n");
89 static void allocate_segment(int *id
, void **address
, size_t number
, size_t size
)
91 *id
= shmget(IPC_PRIVATE
, number
* size
, IPC_CREAT
| 0600);
93 err(EXIT_FAILURE
, "shmget failed to create %zu bytes shared memory", number
* size
);
95 *address
= shmat(*id
, NULL
, 0);
96 if (*address
== (void *)-1)
97 err(EXIT_FAILURE
, "shmat failed");
100 "allocate shared memory segment [id=%d,address=0x%p]\n",
103 memset(*address
, 0, number
* size
);
106 static void remove_segment(int id
, void *address
)
108 if (shmdt(address
) == -1)
109 err(EXIT_FAILURE
, "shmdt failed");
110 if (shmctl(id
, IPC_RMID
, NULL
) == -1)
111 err(EXIT_FAILURE
, "shmctl failed");
114 "remove shared memory segment [id=%d,address=0x%p]\n",
118 static void object_uuid_create(object_t
* object
)
120 uuid_generate_time(object
->uuid
);
123 static void object_uuid_to_string(object_t
* object
, char **string_uuid
)
125 uuid_unparse(object
->uuid
, *string_uuid
);
128 static int object_uuid_compare(const void *object1
, const void *object2
)
130 uuid_t
*uuid1
= &((object_t
*) object1
)->uuid
,
131 *uuid2
= &((object_t
*) object2
)->uuid
;
133 return uuid_compare(*uuid1
, *uuid2
);
136 static void *create_uuids(thread_t
*th
)
140 for (i
= th
->index
; i
< th
->index
+ nobjects
; i
++) {
141 object_t
*obj
= &objects
[i
];
143 object_uuid_create(obj
);
145 obj
->pid
= th
->proc
->pid
;
146 obj
->idx
= th
->index
+ i
;
151 static void *thread_body(void *arg
)
153 thread_t
*th
= (thread_t
*) arg
;
155 return create_uuids(th
);
158 static void create_nthreads(process_t
*proc
, size_t index
)
161 size_t i
, ncreated
= 0;
164 threads
= xcalloc(nthreads
, sizeof(thread_t
));
166 for (i
= 0; i
< nthreads
; i
++) {
167 thread_t
*th
= &threads
[i
];
169 rc
= pthread_attr_init(&th
->thread_attr
);
172 warn("%d: pthread_attr_init failed", proc
->pid
);
178 rc
= pthread_create(&th
->tid
, &th
->thread_attr
, &thread_body
, th
);
182 warn("%d: pthread_create failed", proc
->pid
);
186 LOG(2, (stderr
, "%d: started thread [tid=%jd,index=%zu]\n",
187 proc
->pid
, (intmax_t) th
->tid
, th
->index
));
192 if (ncreated
!= nthreads
)
193 fprintf(stderr
, "%d: %zu threads not created and ~%zu objects will be ignored\n",
194 proc
->pid
, nthreads
- ncreated
,
195 (nthreads
- ncreated
) * nobjects
);
197 for (i
= 0; i
< ncreated
; i
++) {
198 thread_t
*th
= &threads
[i
];
200 rc
= pthread_join(th
->tid
, (void *) &th
->retval
);
203 err(EXIT_FAILURE
, "pthread_join failed");
206 LOG(2, (stderr
, "%d: thread exited [tid=%jd,return=%d]\n",
207 proc
->pid
, (intmax_t) th
->tid
, th
->retval
));
211 static void create_nprocesses(void)
216 process
= xcalloc(nprocesses
, sizeof(process_t
));
218 for (i
= 0; i
< nprocesses
; i
++) {
219 process_t
*proc
= &process
[i
];
224 err(EXIT_FAILURE
, "fork failed");
227 proc
->pid
= getpid();
228 create_nthreads(proc
, i
* nthreads
* nobjects
);
231 default: /* parent */
232 LOG(2, (stderr
, "started process [pid=%d]\n", proc
->pid
));
237 for (i
= 0; i
< nprocesses
; i
++) {
238 process_t
*proc
= &process
[i
];
240 if (waitpid(proc
->pid
, &proc
->status
, 0) == (pid_t
) - 1)
241 err(EXIT_FAILURE
, "waitpid failed");
243 (stderr
, "process exited [pid=%d,status=%d]\n",
244 proc
->pid
, proc
->status
));
248 static void object_dump(size_t idx
, object_t
*obj
)
250 char uuid_string
[UUID_STR_LEN
], *p
;
253 object_uuid_to_string(obj
, &p
);
255 fprintf(stderr
, "object[%zu]: {\n", idx
);
256 fprintf(stderr
, " uuid: <%s>\n", p
);
257 fprintf(stderr
, " idx: %zu\n", obj
->idx
);
258 fprintf(stderr
, " process: %d\n", (int) obj
->pid
);
259 fprintf(stderr
, " thread: %jd\n", (intmax_t) obj
->tid
);
260 fprintf(stderr
, "}\n");
263 #define MSG_TRY_HELP "Try '-h' for help."
265 int main(int argc
, char *argv
[])
267 size_t i
, nfailed
= 0, nignored
= 0;
270 while (((c
= getopt(argc
, argv
, "p:t:o:l:h")) != -1)) {
273 nprocesses
= strtou32_or_err(optarg
, "invalid nprocesses number argument");
276 nthreads
= strtou32_or_err(optarg
, "invalid nthreads number argument");
279 nobjects
= strtou32_or_err(optarg
, "invalid nobjects number argument");
282 loglev
= strtou32_or_err(optarg
, "invalid log level argument");
288 fprintf(stderr
, MSG_TRY_HELP
);
294 errx(EXIT_FAILURE
, "bad usage\n" MSG_TRY_HELP
);
297 fprintf(stderr
, "requested: %zu processes, %zu threads, %zu objects per thread (%zu objects = %zu bytes)\n",
298 nprocesses
, nthreads
, nobjects
,
299 nprocesses
* nthreads
* nobjects
,
300 nprocesses
* nthreads
* nobjects
* sizeof(object_t
));
302 allocate_segment(&shmem_id
, (void **)&objects
,
303 nprocesses
* nthreads
* nobjects
, sizeof(object_t
));
308 for (i
= 0; i
< nprocesses
* nthreads
* nobjects
; i
++)
309 object_dump(i
, &objects
[i
]);
312 qsort(objects
, nprocesses
* nthreads
* nobjects
, sizeof(object_t
),
313 object_uuid_compare
);
315 for (i
= 0; i
< nprocesses
* nthreads
* nobjects
- 1; i
++) {
316 object_t
*obj1
= &objects
[i
],
317 *obj2
= &objects
[i
+ 1];
320 LOG(3, (stderr
, "ignore unused object #%zu\n", i
));
325 if (object_uuid_compare(obj1
, obj2
) == 0) {
327 fprintf(stderr
, "nobjects #%zu and #%zu have duplicate UUIDs\n",
329 object_dump(i
, obj1
),
330 object_dump(i
+ 1, obj2
);
335 remove_segment(shmem_id
, objects
);
337 printf("%zu objects ignored\n", nignored
);
339 printf("test successful (no duplicate UUIDs found)\n");
341 printf("test failed (found %zu duplicate UUIDs)\n", nfailed
);
343 return nfailed
? EXIT_FAILURE
: EXIT_SUCCESS
;