Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:36

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  *
0005  *  This is a simple real-time applications XXX.
0006  *
0007  *  Other POSIX facilities such as XXX, condition, .. is also used
0008  *
0009  * Redistribution and use in source and binary forms, with or without
0010  * modification, are permitted provided that the following conditions
0011  * are met:
0012  * 1. Redistributions of source code must retain the above copyright
0013  *    notice, this list of conditions and the following disclaimer.
0014  * 2. Redistributions in binary form must reproduce the above copyright
0015  *    notice, this list of conditions and the following disclaimer in the
0016  *    documentation and/or other materials provided with the distribution.
0017  *
0018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0028  * POSSIBILITY OF SUCH DAMAGE.
0029  */
0030 
0031 #ifdef HAVE_CONFIG_H
0032 #include "config.h"
0033 #endif
0034 
0035 #define CONFIGURE_INIT
0036 #include "system.h"
0037 #include <pthread.h>  /* thread facilities */
0038 #include <signal.h>   /* signal facilities */
0039 #include <unistd.h>   /* sleep facilities */
0040 #include <sched.h>    /* schedule facilities */
0041 #include <time.h>     /* time facilities */
0042 #include <stdio.h>    /* console facilities */
0043 #include "tmacros.h"
0044 
0045 const char rtems_test_name[] = "PSXCLEANUP";
0046 
0047 #define NUMBER_THREADS 2
0048 pthread_t ThreadIds[NUMBER_THREADS];
0049 
0050 typedef struct {
0051   pthread_mutex_t lock;
0052   pthread_cond_t rcond;
0053   pthread_cond_t wcond;
0054   int lock_count; /* < 0 .. Held by writer. */
0055                   /* > 0 .. Held by lock_count readers. */
0056                   /* = 0 .. Held by nobody. */
0057   int waiting_writers; /* Count of waiting writers. */
0058 } lock_t;
0059 
0060 volatile bool reader_cleanup_ran;
0061 volatile bool release_read_lock_ran;
0062 volatile bool writer_cleanup_ran;
0063 
0064 void waiting_reader_cleanup(void *arg);
0065 void lock_for_read(void *arg);
0066 void release_read_lock(void *arg);
0067 void waiting_writer_cleanup(void *arg);
0068 void lock_for_write(lock_t *l);
0069 void release_write_lock(void *arg);
0070 void initialize_lock_t(lock_t *l);
0071 void *ReaderThread(void *arg);
0072 void *WriterThread(void *arg);
0073 
0074 void waiting_reader_cleanup(void *arg)
0075 {
0076   lock_t *l;
0077 
0078   reader_cleanup_ran = TRUE;
0079 
0080   l = (lock_t *) arg;
0081   pthread_mutex_unlock(&l->lock);
0082 }
0083 
0084 void lock_for_read(void *arg)
0085 {
0086   lock_t *l = arg;
0087 
0088   pthread_mutex_lock(&l->lock);
0089   pthread_cleanup_push(waiting_reader_cleanup, l);
0090   while ((l->lock_count < 0) && (l->waiting_writers != 0))
0091     pthread_cond_wait(&l->rcond, &l->lock);
0092   l->lock_count++;
0093   reader_cleanup_ran = FALSE;
0094 
0095   /*
0096    * Note the pthread_cleanup_pop executes
0097    * waiting_reader_cleanup.
0098    */
0099   pthread_cleanup_pop(1);
0100 
0101   if ( reader_cleanup_ran == FALSE ) {
0102     puts( "reader cleanup did not run" );
0103     rtems_test_exit(0);
0104   }
0105 }
0106 
0107 void release_read_lock(void *arg)
0108 {
0109   lock_t *l = arg;
0110 
0111   release_read_lock_ran = TRUE;
0112   pthread_mutex_lock(&l->lock);
0113   if (--l->lock_count == 0)
0114     pthread_cond_signal(&l->wcond);
0115   pthread_mutex_unlock(&l->lock);
0116 }
0117 
0118 void waiting_writer_cleanup(void *arg)
0119 {
0120   lock_t *l = arg;
0121 
0122   writer_cleanup_ran = TRUE;
0123 
0124   if ((--l->waiting_writers == 0) && (l->lock_count >= 0)) {
0125     /*
0126      * This only happens if we have been canceled.
0127      */
0128     pthread_cond_broadcast(&l->wcond);
0129   }
0130     pthread_mutex_unlock(&l->lock);
0131 }
0132 
0133 void lock_for_write(lock_t *l)
0134 {
0135   pthread_mutex_lock(&l->lock);
0136   l->waiting_writers++;
0137   l->lock_count = -1;
0138 
0139   pthread_cleanup_push(waiting_writer_cleanup, l);
0140 
0141   while (l->lock_count != 0)
0142       pthread_cond_wait(&l->wcond, &l->lock);
0143   l->lock_count = -1;
0144 
0145   /*
0146    * Note the pthread_cleanup_pop executes
0147    * waiting_writer_cleanup.
0148    */
0149   writer_cleanup_ran = FALSE;
0150   pthread_cleanup_pop(1);
0151 
0152   if ( writer_cleanup_ran == FALSE ) {
0153     puts( "writer cleanup did not run" );
0154     rtems_test_exit(0);
0155   }
0156 }
0157 
0158 void release_write_lock(void *arg)
0159 {
0160   lock_t *l = arg;
0161 
0162   writer_cleanup_ran = TRUE;
0163 
0164   /* pthread_mutex_lock(&l->lock); */
0165   l->lock_count = 0;
0166   if (l->waiting_writers == 0)
0167       pthread_cond_broadcast(&l->rcond);
0168   else
0169       pthread_cond_signal(&l->wcond);
0170   /* pthread_mutex_unlock(&l->lock); */
0171 }
0172 
0173 
0174 /*
0175  * This function is called to initialize the read/write lock.
0176  */
0177 void initialize_lock_t(lock_t *l)
0178 {
0179   pthread_mutexattr_t mutexattr;    /* mutex attributes */
0180   pthread_condattr_t  condattr;     /* condition attributes */
0181 
0182   if (pthread_mutexattr_init (&mutexattr) != 0) {
0183     perror ("Error in mutex attribute init\n");
0184   }
0185   if (pthread_mutex_init (&l->lock,&mutexattr) != 0) {
0186     perror ("Error in mutex init");
0187   }
0188 
0189   if (pthread_condattr_init (&condattr) != 0) {
0190      perror ("Error in condition attribute init\n");
0191   }
0192   if (pthread_cond_init (&l->wcond,&condattr) != 0) {
0193     perror ("Error in write condition init");
0194   }
0195   if (pthread_cond_init (&l->rcond,&condattr) != 0) {
0196     perror ("Error in read condition init");
0197   }
0198 
0199   l->lock_count = 0;
0200   l->waiting_writers = 0;
0201 }
0202 
0203 void *ReaderThread(void *arg)
0204 {
0205   lock_t *l = arg;
0206 
0207   puts("Lock for read");
0208   lock_for_read(l);
0209   puts("cleanup push for read");
0210   pthread_cleanup_push(release_read_lock, &l->lock);
0211 
0212   /* Thread has read lock. */
0213   release_read_lock_ran = FALSE;
0214   puts("cleanup pop for read");
0215   pthread_cleanup_pop(1);
0216 
0217   if ( release_read_lock_ran == FALSE ) {
0218     puts( "release read lock did not run" );
0219     rtems_test_exit(0);
0220   }
0221   return NULL;
0222 }
0223 
0224 void *WriterThread(void *arg)
0225 {
0226   lock_t *l = arg;
0227 
0228   puts("Lock for write");
0229   lock_for_write(l);
0230   puts("cleanup push for write");
0231   pthread_cleanup_push(release_write_lock, &l->lock);
0232 
0233   /* Thread has write lock. */
0234   release_write_lock(&l->lock);
0235 
0236   /* do nothing */
0237   puts("do nothing cleanup pop for write");
0238   pthread_cleanup_pop(0);
0239   return NULL;
0240 }
0241 
0242 /*
0243  *  main entry point to the test
0244  */
0245 
0246 void *POSIX_Init(
0247   void *argument
0248 )
0249 {
0250   pthread_attr_t attr;              /* task attributes */
0251   int            status;
0252   lock_t         l;
0253 
0254   TEST_BEGIN();
0255 
0256   /*************** INITIALIZE  ***************/
0257   initialize_lock_t(&l);
0258   if (pthread_attr_init(&attr) != 0) {
0259     perror ("Error in attribute init\n");
0260   }
0261 
0262   /*************** CREATE THREADS  ***************/
0263 
0264   status = pthread_create(&ThreadIds[0], NULL, ReaderThread, &l);
0265   posix_service_failed( status, "pthread_create Reader" );
0266 
0267   sleep(1);
0268 
0269   status = pthread_create(&ThreadIds[1], NULL, WriterThread, &l);
0270   posix_service_failed( status, "pthread_create Writer" );
0271 
0272   sleep(1);
0273 
0274   /*************** END OF TEST *****************/
0275   TEST_END();
0276   rtems_test_exit(0);
0277 }
0278