source: rtems/testsuites/psxtests/psxcleanup/psxcleanup.c @ 927a0a1

4.115
Last change on this file since 927a0a1 was 927a0a1, checked in by Sebastian Huber <sebastian.huber@…>, on 12/02/13 at 07:33:35

posix: Use cleanup contexts on the stack

Provide support for latest Newlib <pthread.h> change. The cleanup
contexts are stored on the thread stack. This is conformant with the
POSIX requirements for the pthread_cleanup_push() and
pthread_cleanup_pop() statement pair.

Passing an invalid pointer as the routine to pthread_cleanup_push() is
now a usage error and the behaviour is undefined.

  • Property mode set to 100644
File size: 5.8 KB
Line 
1/*
2 *
3 *  This is a simple real-time applications XXX.
4 *
5 *  Other POSIX facilities such as XXX, condition, .. is also used
6 *
7 *  The license and distribution terms for this file may be
8 *  found in the file LICENSE in this distribution or at
9 *  http://www.rtems.com/license/LICENSE.
10 */
11
12#ifdef HAVE_CONFIG_H
13#include "config.h"
14#endif
15
16#define CONFIGURE_INIT
17#include "system.h"
18#include <pthread.h>  /* thread facilities */
19#include <signal.h>   /* signal facilities */
20#include <unistd.h>   /* sleep facilities */
21#include <sched.h>    /* schedule facilities */
22#include <time.h>     /* time facilities */
23#include <stdio.h>    /* console facilities */
24#include "tmacros.h"
25
26#define NUMBER_THREADS 2
27pthread_t ThreadIds[NUMBER_THREADS];
28
29typedef struct {
30  pthread_mutex_t lock;
31  pthread_cond_t rcond;
32  pthread_cond_t wcond;
33  int lock_count; /* < 0 .. Held by writer. */
34                  /* > 0 .. Held by lock_count readers. */
35                  /* = 0 .. Held by nobody. */
36  int waiting_writers; /* Count of waiting writers. */
37} lock_t;
38
39volatile bool reader_cleanup_ran;
40volatile bool release_read_lock_ran;
41volatile bool writer_cleanup_ran;
42
43void waiting_reader_cleanup(void *arg);
44void lock_for_read(void *arg);
45void release_read_lock(void *arg);
46void waiting_writer_cleanup(void *arg);
47void lock_for_write(lock_t *l);
48void release_write_lock(void *arg);
49void initialize_lock_t(lock_t *l);
50void *ReaderThread(void *arg);
51void *WriterThread(void *arg);
52
53void waiting_reader_cleanup(void *arg)
54{
55  lock_t *l;
56
57  reader_cleanup_ran = TRUE;
58
59  l = (lock_t *) arg;
60  pthread_mutex_unlock(&l->lock);
61}
62
63void lock_for_read(void *arg)
64{
65  lock_t *l = arg;
66
67  pthread_mutex_lock(&l->lock);
68  pthread_cleanup_push(waiting_reader_cleanup, l);
69  while ((l->lock_count < 0) && (l->waiting_writers != 0))
70    pthread_cond_wait(&l->rcond, &l->lock);
71  l->lock_count++;
72  reader_cleanup_ran = FALSE;
73
74  /*
75   * Note the pthread_cleanup_pop executes
76   * waiting_reader_cleanup.
77   */
78  pthread_cleanup_pop(1);
79
80  if ( reader_cleanup_ran == FALSE ) {
81    puts( "reader cleanup did not run" );
82    rtems_test_exit(0);
83  }
84}
85
86void release_read_lock(void *arg)
87{
88  lock_t *l = arg;
89
90  release_read_lock_ran = TRUE;
91  pthread_mutex_lock(&l->lock);
92  if (--l->lock_count == 0)
93    pthread_cond_signal(&l->wcond);
94  pthread_mutex_unlock(&l->lock);
95}
96
97void waiting_writer_cleanup(void *arg)
98{
99  lock_t *l = arg;
100
101  writer_cleanup_ran = TRUE;
102
103  if ((--l->waiting_writers == 0) && (l->lock_count >= 0)) {
104    /*
105     * This only happens if we have been canceled.
106     */
107    pthread_cond_broadcast(&l->wcond);
108  }
109    pthread_mutex_unlock(&l->lock);
110}
111
112void lock_for_write(lock_t *l)
113{
114  pthread_mutex_lock(&l->lock);
115  l->waiting_writers++;
116  l->lock_count = -1;
117
118  pthread_cleanup_push(waiting_writer_cleanup, l);
119
120  while (l->lock_count != 0)
121      pthread_cond_wait(&l->wcond, &l->lock);
122  l->lock_count = -1;
123
124  /*
125   * Note the pthread_cleanup_pop executes
126   * waiting_writer_cleanup.
127   */
128  writer_cleanup_ran = FALSE;
129  pthread_cleanup_pop(1);
130
131  if ( writer_cleanup_ran == FALSE ) {
132    puts( "writer cleanup did not run" );
133    rtems_test_exit(0);
134  }
135}
136
137void release_write_lock(void *arg)
138{
139  lock_t *l = arg;
140
141  writer_cleanup_ran = TRUE;
142
143  /* pthread_mutex_lock(&l->lock); */
144  l->lock_count = 0;
145  if (l->waiting_writers == 0)
146      pthread_cond_broadcast(&l->rcond);
147  else
148      pthread_cond_signal(&l->wcond);
149  /* pthread_mutex_unlock(&l->lock); */
150}
151
152
153/*
154 * This function is called to initialize the read/write lock.
155 */
156void initialize_lock_t(lock_t *l)
157{
158  pthread_mutexattr_t mutexattr;    /* mutex attributes */
159  pthread_condattr_t  condattr;     /* condition attributes */
160
161  if (pthread_mutexattr_init (&mutexattr) != 0) {
162    perror ("Error in mutex attribute init\n");
163  }
164  if (pthread_mutex_init (&l->lock,&mutexattr) != 0) {
165    perror ("Error in mutex init");
166  }
167
168  if (pthread_condattr_init (&condattr) != 0) {
169     perror ("Error in condition attribute init\n");
170  }
171  if (pthread_cond_init (&l->wcond,&condattr) != 0) {
172    perror ("Error in write condition init");
173  }
174  if (pthread_cond_init (&l->rcond,&condattr) != 0) {
175    perror ("Error in read condition init");
176  }
177
178  l->lock_count = 0;
179  l->waiting_writers = 0;
180}
181
182void *ReaderThread(void *arg)
183{
184  lock_t *l = arg;
185
186  puts("Lock for read");
187  lock_for_read(l);
188  puts("cleanup push for read");
189  pthread_cleanup_push(release_read_lock, &l->lock);
190
191  /* Thread has read lock. */
192  release_read_lock_ran = FALSE;
193  puts("cleanup pop for read");
194  pthread_cleanup_pop(1);
195
196  if ( release_read_lock_ran == FALSE ) {
197    puts( "release read lock did not run" );
198    rtems_test_exit(0);
199  }
200  return NULL;
201}
202
203void *WriterThread(void *arg)
204{
205  lock_t *l = arg;
206
207  puts("Lock for write");
208  lock_for_write(l);
209  puts("cleanup push for write");
210  pthread_cleanup_push(release_write_lock, &l->lock);
211
212  /* Thread has write lock. */
213  release_write_lock(&l->lock);
214
215  /* do nothing */
216  puts("do nothing cleanup pop for write");
217  pthread_cleanup_pop(0);
218  return NULL;
219}
220
221/*
222 *  main entry point to the test
223 */
224
225void *POSIX_Init(
226  void *argument
227)
228{
229  pthread_attr_t attr;              /* task attributes */
230  int            status;
231  lock_t         l;
232
233  puts( "\n\n*** POSIX CLEANUP TEST ***" );
234
235  /*************** INITIALIZE  ***************/
236  initialize_lock_t(&l);
237  if (pthread_attr_init(&attr) != 0) {
238    perror ("Error in attribute init\n");
239  }
240
241  /*************** CREATE THREADS  ***************/
242
243  status = pthread_create(&ThreadIds[0], NULL, ReaderThread, &l);
244  posix_service_failed( status, "pthread_create Reader" );
245
246  sleep(1);
247
248  status = pthread_create(&ThreadIds[1], NULL, WriterThread, &l);
249  posix_service_failed( status, "pthread_create Writer" );
250
251  sleep(1);
252
253  /*************** END OF TEST *****************/
254  puts( "*** END OF POSIX CLEANUP TEST ***\n" );
255  rtems_test_exit(0);
256}
257
Note: See TracBrowser for help on using the repository browser.