1/*
2 * Copyright (c) 2002, Intel Corporation. All rights reserved.
3 * This file is licensed under the GPL license.  For the full content
4 * of this license, see the COPYING file at the top level of this
5 * source tree.
6 *
7 *	Test pthread_spin_init(pthread_spinlock_t *lock, int pshared)
8 *
9 * 	If the Thread Process-Shared Synchronization option is supported
10 * 	and the value of pshared is PTHREAD_PROCESS_PRIVATE, or if the option
11 * 	is not supported, the spin lock shall only be operated upon by threads created
12 * 	within the same process as the thread that initialized the spin lock.
13 *	If threads of different processed attempt to operation on such a spin
14 *	lock, the behavior is undefined.
15 *
16 * NOTE: This case will always PASS
17 *
18 * steps:
19 *	1. Create a piece of shared memory object, create a spin lock 'spinlock' and
20 *	   set the PTHREAD_PROCESS_PRIVATE attribute.
21 *	2. Parent map the shared memory to its memory space, put 'spinlock' into it;
22 *	3. Parent get the spin lock;
23 *	4. Fork to create child
24 *	5. Child map the shared memory to its memory space;
25 *	6. Child call pthread_spin_trylock()
26 *	7. Main unlock
27 *	8. Child call pthread_spin_trylock()
28 */
29
30
31#define _XOPEN_SOURCE 600
32#include <pthread.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <unistd.h>
36#include <errno.h>
37#include <string.h>
38#include <sys/mman.h>
39#include <fcntl.h>
40#include <sys/wait.h>
41#include "posixtest.h"
42
43struct shmstruct{
44	pthread_spinlock_t spinlock;
45	int data;
46} *spinlock_data;
47
48int main()
49{
50
51	int pshared;
52
53	/* Make sure there is process-shared capability. */
54	#ifdef PTHREAD_PROCESS_PRIVATE
55	pshared = PTHREAD_PROCESS_PRIVATE;
56	#else
57 	pshared = -1;
58	#endif
59
60	char shm_name[] = "tmp_pthread_spinlock_init";
61	int shm_fd;
62	int pid;
63	int rc;
64
65	/* Create shared object */
66	shm_unlink(shm_name);
67	shm_fd = shm_open(shm_name, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
68	if(shm_fd == -1)
69	{
70		perror("Error at shm_open()");
71		return PTS_UNRESOLVED;
72	}
73
74        if(ftruncate(shm_fd, sizeof(struct shmstruct)) != 0) {
75                perror("Error at ftruncate()");
76                shm_unlink(shm_name);
77                return PTS_UNRESOLVED;
78        }
79
80	/* Map the shared memory object to parent's memory */
81	spinlock_data = mmap(NULL, sizeof(struct shmstruct), PROT_READ|PROT_WRITE,
82				MAP_SHARED, shm_fd, 0);
83
84	if(spinlock_data == MAP_FAILED)
85	{
86		perror("Error at first mmap()");
87                shm_unlink(shm_name);
88		return PTS_UNRESOLVED;
89	}
90
91	if((pthread_spin_init(&(spinlock_data->spinlock), pshared)) != 0)
92	{
93		printf("Test FAILED: Error at pthread_rwlock_init()\n");
94		return PTS_FAIL;
95	}
96
97	printf("main: attempt spin lock\n");
98	if((pthread_spin_lock(&(spinlock_data->spinlock))) != 0)
99	{
100		printf("Error at pthread_spin_lock()\n");
101		return PTS_UNRESOLVED;
102	}
103	printf("main: acquired spin lock\n");
104
105	/* Initialized spinlock data */
106	spinlock_data->data = 0;
107
108	pid = fork();
109	if(pid == -1)
110	{
111		perror("Error at fork()");
112		return PTS_UNRESOLVED;
113	}
114	else if(pid > 0)
115	{
116		/* Parent */
117		/* wait until child writes to spinlock data */
118		while(spinlock_data->data != 1)
119			sleep(1);
120
121		printf("main: unlock spin lock\n");
122		if(pthread_spin_unlock(&(spinlock_data->spinlock)) != 0)
123		{
124			printf("main: error at pthread_spin_unlock()\n");
125			return PTS_UNRESOLVED;
126		}
127
128		/* Tell child that parent unlocked the spin lock */
129		spinlock_data->data = 2;
130
131		/* Wait until child ends */
132		wait(NULL);
133
134		if((shm_unlink(shm_name)) != 0)
135		{
136			perror("Error at shm_unlink()");
137			return PTS_UNRESOLVED;
138		}
139
140		printf("Test PASSED\n");
141		return PTS_PASS;
142	}
143	else
144	{
145		/* Child */
146		/* Map the shared object to child's memory */
147		spinlock_data = mmap(NULL, sizeof(struct shmstruct), PROT_READ|PROT_WRITE,
148				MAP_SHARED, shm_fd, 0);
149
150		if(spinlock_data == MAP_FAILED)
151		{
152			perror("child : Error at mmap()");
153			return PTS_UNRESOLVED;
154		}
155
156		printf("child: attempt spin lock\n");
157		rc = pthread_spin_trylock(&(spinlock_data->spinlock));
158		if( rc != EBUSY)
159			printf("child: get return code %d, %s\n", rc, strerror(rc));
160		else
161			printf("child: correctly got EBUSY\n");
162
163		/* Tell parent it can unlock now */
164		spinlock_data->data = 1;
165
166		while(spinlock_data->data != 2)
167			sleep(1);
168
169		printf("child: attempt spin lock\n");
170		rc = pthread_spin_trylock(&(spinlock_data->spinlock));
171		if(rc == 0)
172			printf("child: acquired spin lock\n");
173		else
174			printf("child: get return code %d, %s\n", rc, strerror(rc));
175
176		printf("child: unlock spin lock\n");
177		if(pthread_spin_unlock(&(spinlock_data->spinlock)) != 0)
178		{
179			printf("Child: error at pthread_spin_unlock()\n");
180			return PTS_UNRESOLVED;
181		}
182
183		if(pthread_spin_destroy(&(spinlock_data->spinlock)) != 0)
184		{
185			printf("Child: error at pthread_spin_destroy()\n");
186			return PTS_UNRESOLVED;
187		}
188	}
189}
190