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 that pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock)
8 *
9 *	The timeout shall expire when the absolute time specified by abs_timeout passes,
10 *	as measured by the clock on which timeouts are based (that is, when the
11 *	value of that clock equals or exceeds abs_timeout), or if the absolute time
12 *	specified by abs_timeout has already been passed at the time of the call.
13 *
14 * Steps:
15 * 1.  Initialize 'rwlock'
16 * 2.  Main thread locks 'rwlock' for writing with pthread_rwlock_wrlock()
17 * 3.  Create a child thread, specify a 'abs_timeout' as being the current time _minus_ a
18 *     timeout period, meaning this will ensure that the abs_timeout would have already
19 *     passed.
20 * 4.  The thread locks 'rwlock' for writing, using pthread_rwlock_timedwrlock(). Should
21 *	get an ETIMEOUT error.
22 */
23
24#define _XOPEN_SOURCE 600
25
26#include <pthread.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <unistd.h>
30#include <errno.h>
31#include "posixtest.h"
32
33#define TIMEOUT 1
34
35static pthread_rwlock_t rwlock;
36static int thread_state;
37static int currsec1, currsec2;
38static int expired;
39
40/* thread_state indicates child thread state:
41	1: not in child thread yet;
42	2: just enter child thread ;
43	3: just before child thread exit;
44*/
45
46#define NOT_CREATED_THREAD 1
47#define ENTERED_THREAD 2
48#define EXITING_THREAD 3
49
50static void* fn(void *arg)
51{
52	struct timespec abs_timeout;
53	int rc;
54	thread_state = ENTERED_THREAD;
55
56	/* Absolute time, not relative. */
57	abs_timeout.tv_sec = currsec1 - TIMEOUT;
58	abs_timeout.tv_nsec = 0;
59
60	printf("thread: attempt timed write-lock\n");
61	rc = pthread_rwlock_timedwrlock(&rwlock, &abs_timeout);
62	if(rc  == ETIMEDOUT)
63	{
64		printf("thread: timer expired\n");
65		expired = 1;
66	}
67	else if(rc == 0)
68	{
69		printf("thread: acquired write lock\n");
70		expired = 0;
71		printf("thread: unlock write lock\n");
72		if(pthread_rwlock_unlock(&rwlock) != 0)
73		{
74			printf("thread: failed to release lock\n");
75			exit(PTS_UNRESOLVED);
76		}
77	}
78	else
79	{
80		printf("Error in pthread_rwlock_timedwrlock(), error code:%d.\n", rc);
81		exit(PTS_UNRESOLVED);
82	}
83
84	/* Get time after the mutex timed out in locking. */
85	currsec2 = time(NULL);
86	thread_state = EXITING_THREAD;
87	pthread_exit(0);
88	return NULL;
89}
90
91int main()
92{
93	int cnt = 0;
94	pthread_t thread1;
95
96	if(pthread_rwlock_init(&rwlock, NULL) != 0)
97	{
98		printf("Error at pthread_rwlock_init()\n");
99		return PTS_UNRESOLVED;
100	}
101
102	printf("main: attempt write lock\n");
103	/* We have no lock, this write lock should succeed */
104	if(pthread_rwlock_wrlock(&rwlock) != 0)
105	{
106		printf("Error at pthread_rwlock_wrlock()\n");
107		return PTS_UNRESOLVED;
108	}
109	printf("main: acquired write lock\n");
110
111	thread_state = NOT_CREATED_THREAD;
112	printf("main: create thread\n");
113	if(pthread_create(&thread1, NULL, fn, NULL) != 0)
114	{
115		printf("Error creating thread\n");
116		return PTS_UNRESOLVED;
117	}
118
119	/* If the shared data is not altered by child after 3 seconds,
120	   we regard it as blocked */
121	/* We expect the thread _NOT_ to block */
122	cnt = 0;
123	do{
124		sleep(1);
125	}while (thread_state !=EXITING_THREAD && cnt++ < 3);
126
127	if(thread_state == EXITING_THREAD)
128	{
129		/* the child thread does not block, check the time expired or not */
130		if(expired != 1)
131		{
132			printf("Test FAILED: abs_timeout should expire\n");
133			exit(PTS_FAIL);
134		}
135		else
136			printf("thread correctly expired and did not wait\n");
137	}
138	else if(thread_state == ENTERED_THREAD)
139	{
140		printf("Test FAILED: thread blocked even when the timer expired\n");
141		exit(PTS_FAIL);
142	}
143	else
144	{
145		printf("Unexpected thread state %d\n", thread_state);
146		exit(PTS_UNRESOLVED);
147	}
148
149	printf("main: unlock write lock\n");
150	if(pthread_rwlock_unlock(&rwlock) != 0)
151	{
152		printf("main: Error at pthread_rwlock_unlock()\n");
153		return PTS_UNRESOLVED;
154	}
155
156	if(pthread_join(thread1, NULL) != 0)
157	{
158		printf("main: Error at pthread_join()\n");
159		return PTS_UNRESOLVED;
160	}
161
162	if(pthread_rwlock_destroy(&rwlock) != 0)
163	{
164		printf("main: Error at pthread_rwlockattr_destroy()\n");
165		return PTS_UNRESOLVED;
166	}
167
168	printf("Test PASSED\n");
169	return PTS_PASS;
170}
171