mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-10-31 22:10:34 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			250 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			250 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Verify that condition variables synchronized by PI mutexes don't hang.
 | |
|    Copyright (C) 2012-2017 Free Software Foundation, Inc.
 | |
|    This file is part of the GNU C Library.
 | |
| 
 | |
|    The GNU C Library is free software; you can redistribute it and/or
 | |
|    modify it under the terms of the GNU Lesser General Public
 | |
|    License as published by the Free Software Foundation; either
 | |
|    version 2.1 of the License, or (at your option) any later version.
 | |
| 
 | |
|    The GNU C Library is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|    Lesser General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU Lesser General Public
 | |
|    License along with the GNU C Library; if not, see
 | |
|    <http://www.gnu.org/licenses/>.  */
 | |
| 
 | |
| #include <pthread.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <errno.h>
 | |
| #include <sys/types.h>
 | |
| #include <sys/syscall.h>
 | |
| #include <unistd.h>
 | |
| #include <sys/time.h>
 | |
| #include <time.h>
 | |
| 
 | |
| #define THREADS_NUM 5
 | |
| #define MAXITER 50000
 | |
| 
 | |
| static pthread_mutex_t mutex;
 | |
| static pthread_mutexattr_t mutex_attr;
 | |
| static pthread_cond_t cond;
 | |
| static pthread_t threads[THREADS_NUM];
 | |
| static int pending = 0;
 | |
| 
 | |
| typedef void * (*threadfunc) (void *);
 | |
| 
 | |
| void *
 | |
| thread_fun_timed (void *arg)
 | |
| {
 | |
|   int *ret = arg;
 | |
|   int rv, i;
 | |
| 
 | |
|   printf ("Started thread_fun_timed[%d]\n", *ret);
 | |
| 
 | |
|   for (i = 0; i < MAXITER / THREADS_NUM; i++)
 | |
|     {
 | |
|       rv = pthread_mutex_lock (&mutex);
 | |
|       if (rv)
 | |
|         {
 | |
| 	  printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv);
 | |
| 	  *ret = 1;
 | |
| 	  goto out;
 | |
| 	}
 | |
| 
 | |
|       while (!pending)
 | |
| 	{
 | |
| 	  struct timespec ts;
 | |
| 	  clock_gettime(CLOCK_REALTIME, &ts);
 | |
| 	  ts.tv_sec += 20;
 | |
| 	  rv = pthread_cond_timedwait (&cond, &mutex, &ts);
 | |
| 
 | |
| 	  /* There should be no timeout either.  */
 | |
| 	  if (rv)
 | |
|             {
 | |
| 	      printf ("pthread_cond_wait: %s(%d)\n", strerror (rv), rv);
 | |
| 	      *ret = 1;
 | |
| 	      goto out;
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
|       pending--;
 | |
| 
 | |
|       rv = pthread_mutex_unlock (&mutex);
 | |
|       if (rv)
 | |
|         {
 | |
| 	  printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv);
 | |
| 	  *ret = 1;
 | |
| 	  goto out;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   *ret = 0;
 | |
| 
 | |
| out:
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| void *
 | |
| thread_fun (void *arg)
 | |
| {
 | |
|   int *ret = arg;
 | |
|   int rv, i;
 | |
| 
 | |
|   printf ("Started thread_fun[%d]\n", *ret);
 | |
| 
 | |
|   for (i = 0; i < MAXITER / THREADS_NUM; i++)
 | |
|     {
 | |
|       rv = pthread_mutex_lock (&mutex);
 | |
|       if (rv)
 | |
|         {
 | |
| 	  printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv);
 | |
| 	  *ret = 1;
 | |
| 	  goto out;
 | |
| 	}
 | |
| 
 | |
|       while (!pending)
 | |
| 	{
 | |
| 	  rv = pthread_cond_wait (&cond, &mutex);
 | |
| 
 | |
| 	  if (rv)
 | |
|             {
 | |
| 	      printf ("pthread_cond_wait: %s(%d)\n", strerror (rv), rv);
 | |
| 	      *ret = 1;
 | |
| 	      goto out;
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
|       pending--;
 | |
| 
 | |
|       rv = pthread_mutex_unlock (&mutex);
 | |
|       if (rv)
 | |
|         {
 | |
| 	  printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv);
 | |
| 	  *ret = 1;
 | |
| 	  goto out;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   *ret = 0;
 | |
| 
 | |
| out:
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| static int
 | |
| do_test_wait (threadfunc f)
 | |
| {
 | |
|   int i;
 | |
|   int rv;
 | |
|   int counter = 0;
 | |
|   int retval[THREADS_NUM];
 | |
| 
 | |
|   puts ("Starting test");
 | |
| 
 | |
|   rv = pthread_mutexattr_init (&mutex_attr);
 | |
|   if (rv)
 | |
|     {
 | |
|       printf ("pthread_mutexattr_init: %s(%d)\n", strerror (rv), rv);
 | |
|       return 1;
 | |
|     }
 | |
| 
 | |
|   rv = pthread_mutexattr_setprotocol (&mutex_attr, PTHREAD_PRIO_INHERIT);
 | |
|   if (rv)
 | |
|     {
 | |
|       printf ("pthread_mutexattr_setprotocol: %s(%d)\n", strerror (rv), rv);
 | |
|       return 1;
 | |
|     }
 | |
| 
 | |
|   rv = pthread_mutex_init (&mutex, &mutex_attr);
 | |
|   if (rv)
 | |
|     {
 | |
|       printf ("pthread_mutex_init: %s(%d)\n", strerror (rv), rv);
 | |
|       return 1;
 | |
|     }
 | |
| 
 | |
|   rv = pthread_cond_init (&cond, NULL);
 | |
|   if (rv)
 | |
|     {
 | |
|       printf ("pthread_cond_init: %s(%d)\n", strerror (rv), rv);
 | |
|       return 1;
 | |
|     }
 | |
| 
 | |
|   for (i = 0; i < THREADS_NUM; i++)
 | |
|     {
 | |
|       retval[i] = i;
 | |
|       rv = pthread_create (&threads[i], NULL, f, &retval[i]);
 | |
|       if (rv)
 | |
|         {
 | |
|           printf ("pthread_create: %s(%d)\n", strerror (rv), rv);
 | |
|           return 1;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   for (; counter < MAXITER; counter++)
 | |
|     {
 | |
|       rv = pthread_mutex_lock (&mutex);
 | |
|       if (rv)
 | |
|         {
 | |
|           printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv);
 | |
|           return 1;
 | |
|         }
 | |
| 
 | |
|       if (!(counter % 100))
 | |
| 	printf ("counter: %d\n", counter);
 | |
|       pending += 1;
 | |
| 
 | |
|       rv = pthread_cond_signal (&cond);
 | |
|       if (rv)
 | |
|         {
 | |
|           printf ("pthread_cond_signal: %s(%d)\n", strerror (rv), rv);
 | |
|           return 1;
 | |
|         }
 | |
| 
 | |
|       rv = pthread_mutex_unlock (&mutex);
 | |
|       if (rv)
 | |
|         {
 | |
|           printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv);
 | |
|           return 1;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   for (i = 0; i < THREADS_NUM; i++)
 | |
|     {
 | |
|       void *ret;
 | |
|       rv = pthread_join (threads[i], &ret);
 | |
|       if (rv)
 | |
|         {
 | |
|           printf ("pthread_join: %s(%d)\n", strerror (rv), rv);
 | |
|           return 1;
 | |
|         }
 | |
|       if (ret && *(int *)ret)
 | |
|         {
 | |
| 	  printf ("Thread %d returned with an error\n", i);
 | |
| 	  return 1;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int
 | |
| do_test (void)
 | |
| {
 | |
|   puts ("Testing pthread_cond_wait");
 | |
|   int ret = do_test_wait (thread_fun);
 | |
|   if (ret)
 | |
|     return ret;
 | |
| 
 | |
|   puts ("Testing pthread_cond_timedwait");
 | |
|   return do_test_wait (thread_fun_timed);
 | |
| }
 | |
| 
 | |
| #define TIMEOUT 20
 | |
| #define TEST_FUNCTION do_test ()
 | |
| #include "../test-skeleton.c"
 |