1/*
2 *  This program is free software; you can redistribute it and/or modify
3 *  it under the terms of the GNU General Public License version 2.
4 *
5 *  This program is distributed in the hope that it will be useful,
6 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
7 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
8 *  GNU General Public License for more details.
9 *
10 * Test that the check for the existence of the shared memory object and the
11 * creation of the object if it does not exist is atomic with respect to other
12 * processes executing shm_open() naming the same shared memory object with
13 * O_EXCL and O_CREAT set.
14 *
15 * This test launch NPROCESS processes which all try to open NLOOP shared
16 * memory objects. If an unexpected error occurs or if the number of created
17 * objects is not NLOOP, the test failed. In other case the test is unresolved.
18 */
19
20/* ftruncate was formerly an XOPEN extension. We define _XOPEN_SOURCE here to
21   avoid warning if the implementation does not program ftruncate as a base
22   interface */
23
24/* adam.li: 2004-04-30: Rewrite the test case. The idea is that with
25   O_CREAT and O_EXCL specified, to shm_open() a object can only success
26   once, although multiple processes might open with the same name at the
27   same time.
28 */
29#define _XOPEN_SOURCE 600
30
31#include <errno.h>
32#include <fcntl.h>
33#include <semaphore.h>
34#include <stdlib.h>
35#include <stdio.h>
36#include <sys/mman.h>
37#include <sys/stat.h>
38#include <sys/wait.h>
39#include <time.h>
40#include <unistd.h>
41#include "posixtest.h"
42
43#define NAME_SIZE 20
44#define SHM_NAME "/posixtest_23-1_%d"
45
46/* The processes communicate by a shared memory object */
47#define SHM_RESULT_NAME "/result_23-1"
48
49#define NPROCESS 1000		/* Number of concurrent processes */
50#define NLOOP 1000		/* Number of shared memory object */
51
52char name[NAME_SIZE];
53int *create_cnt;
54sem_t *sem;
55
56int child_func(void)
57{
58	int i, fd;
59	struct timespec ts = {.tv_sec = 0,.tv_nsec = 0 };
60	int msec = 0;
61
62	sleep(1);
63	srand(time(NULL));
64	for (i = 0; i < NLOOP; i++) {
65		sprintf(name, SHM_NAME, i);
66		fd = shm_open(name, O_RDONLY | O_CREAT | O_EXCL,
67			      S_IRUSR | S_IWUSR);
68		if (fd != -1) {
69			sem_wait(sem);
70			//fprintf(stderr, "%d: %d\n", getpid(), *create_cnt);
71			(*create_cnt)++;
72			sem_post(sem);
73		}
74		/* get a random number [0, 20] */
75		msec = (int)(20.0 * rand() / RAND_MAX);
76		ts.tv_nsec = msec * 1000000;
77		nanosleep(&ts, NULL);
78	}
79	return 0;
80}
81
82int main(void)
83{
84	int i, pid, result_fd;
85	char semname[20];
86
87	snprintf(semname, 20, "/sem23-1_%d", getpid());
88	sem = sem_open(semname, O_CREAT, 0777, 1);
89	if (sem == SEM_FAILED || sem == NULL) {
90		perror("error at sem_open");
91		return PTS_UNRESOLVED;
92	}
93	sem_unlink(semname);
94
95	result_fd = shm_open(SHM_RESULT_NAME,
96			     O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
97	if (result_fd == -1) {
98		perror("An error occurs when calling shm_open()");
99		return PTS_UNRESOLVED;
100	}
101	shm_unlink(SHM_RESULT_NAME);
102	if (ftruncate(result_fd, sizeof(*create_cnt)) != 0) {
103		perror("An error occurs when calling ftruncate()");
104		shm_unlink(SHM_RESULT_NAME);
105		return PTS_UNRESOLVED;
106	}
107
108	create_cnt = mmap(NULL, sizeof(*create_cnt), PROT_WRITE | PROT_READ,
109			  MAP_SHARED, result_fd, 0);
110	if (create_cnt == MAP_FAILED) {
111		perror("An error occurs when calling mmap()");
112		shm_unlink(SHM_RESULT_NAME);
113		return PTS_UNRESOLVED;
114	}
115
116	*create_cnt = 0;
117
118	for (i = 0; i < NPROCESS; i++) {
119		pid = fork();
120		if (pid == -1) {
121			perror("An error occurs when calling fork()");
122			return PTS_UNRESOLVED;
123		} else if (pid == 0) {
124			child_func();
125			exit(0);
126		}
127	}
128
129	while (wait(NULL) > 0) ;
130
131	for (i = 0; i < NLOOP; i++) {
132		sprintf(name, SHM_NAME, i);
133		shm_unlink(name);
134	}
135
136	fprintf(stderr, "create_cnt: %d\n", *create_cnt);
137	if (*create_cnt != NLOOP) {
138		printf("Test FAILED\n");
139		return PTS_FAIL;
140	}
141
142	return PTS_PASS;
143}
144