Blame stdlib/test-dlclose-exit-race.c

Packit 6c4009
/* Test for exit/dlclose race (Bug 22180).
Packit 6c4009
   Copyright (C) 2017-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
/* This file must be run from within a directory called "stdlib".  */
Packit 6c4009
Packit 6c4009
/* This test verifies that when dlopen in one thread races against exit
Packit 6c4009
   in another thread, we don't call registered destructor twice.
Packit 6c4009
Packit 6c4009
   Expected result:
Packit 6c4009
     second
Packit 6c4009
     first
Packit 6c4009
     ... clean termination
Packit 6c4009
*/
Packit 6c4009
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <semaphore.h>
Packit 6c4009
#include <support/check.h>
Packit 6c4009
#include <support/xdlfcn.h>
Packit 6c4009
#include <support/xthread.h>
Packit 6c4009
Packit 6c4009
/* Semaphore to ensure we have a happens-before between the first function
Packit 6c4009
   starting and exit being called.  */
Packit 6c4009
sem_t order1;
Packit 6c4009
Packit 6c4009
/* Semaphore to ensure we have a happens-before between the second function
Packit 6c4009
   starting and the first function returning.  */
Packit 6c4009
sem_t order2;
Packit 6c4009
Packit 6c4009
void *
Packit 6c4009
exit_thread (void *arg)
Packit 6c4009
{
Packit 6c4009
  /* Wait for the dlclose to start...  */
Packit 6c4009
  sem_wait (&order1;;
Packit 6c4009
  /* Then try to run the exit sequence which should call all
Packit 6c4009
     __cxa_atexit registered functions and in parallel with
Packit 6c4009
     the executing dlclose().  */
Packit 6c4009
  exit (0);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
last (void)
Packit 6c4009
{
Packit 6c4009
  /* Let dlclose thread proceed.  */
Packit 6c4009
  sem_post (&order2;;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
main (void)
Packit 6c4009
{
Packit 6c4009
  void *dso;
Packit 6c4009
  pthread_t thread;
Packit 6c4009
Packit 6c4009
  atexit (last);
Packit 6c4009
Packit 6c4009
  dso = xdlopen ("$ORIGIN/test-dlclose-exit-race-helper.so",
Packit 6c4009
		 RTLD_NOW|RTLD_GLOBAL);
Packit 6c4009
  thread = xpthread_create (NULL, exit_thread, NULL);
Packit 6c4009
Packit 6c4009
  xdlclose (dso);
Packit 6c4009
  xpthread_join (thread);
Packit 6c4009
Packit 6c4009
  FAIL_EXIT1 ("Did not terminate via exit(0) in exit_thread() as expected.");
Packit 6c4009
}