(root)/
glibc-2.38/
sysdeps/
pthread/
tst-flock2.c
       1  /* Copyright (C) 2002-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <errno.h>
      19  #include <pthread.h>
      20  #include <stdio.h>
      21  #include <stdlib.h>
      22  #include <unistd.h>
      23  #include <sys/file.h>
      24  #include <sys/mman.h>
      25  #include <sys/wait.h>
      26  
      27  #include <support/xunistd.h>
      28  
      29  static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
      30  static pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;
      31  static int fd;
      32  
      33  
      34  static void *
      35  tf (void *arg)
      36  {
      37    struct flock fl =
      38      {
      39        .l_type = F_WRLCK,
      40        .l_start = 0,
      41        .l_whence = SEEK_SET,
      42        .l_len = 10
      43      };
      44    if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0)
      45      {
      46        puts ("fourth fcntl failed");
      47        exit (1);
      48      }
      49  
      50    pthread_mutex_unlock (&lock);
      51  
      52    pthread_mutex_lock (&lock2);
      53  
      54    return NULL;
      55  }
      56  
      57  
      58  static int
      59  do_test (void)
      60  {
      61    char tmp[] = "/tmp/tst-flock2-XXXXXX";
      62  
      63    fd = mkstemp (tmp);
      64    if (fd == -1)
      65      {
      66        puts ("mkstemp failed");
      67        return 1;
      68      }
      69  
      70    unlink (tmp);
      71  
      72    int i;
      73    for (i = 0; i < 20; ++i)
      74      xwrite (fd, "foobar xyzzy", 12);
      75  
      76    pthread_barrier_t *b;
      77    b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE,
      78  	    MAP_SHARED, fd, 0);
      79    if (b == MAP_FAILED)
      80      {
      81        puts ("mmap failed");
      82        return 1;
      83      }
      84  
      85    pthread_barrierattr_t ba;
      86    if (pthread_barrierattr_init (&ba) != 0)
      87      {
      88        puts ("barrierattr_init failed");
      89        return 1;
      90      }
      91  
      92    if (pthread_barrierattr_setpshared (&ba, PTHREAD_PROCESS_SHARED) != 0)
      93      {
      94        puts ("barrierattr_setpshared failed");
      95        return 1;
      96      }
      97  
      98    if (pthread_barrier_init (b, &ba, 2) != 0)
      99      {
     100        puts ("barrier_init failed");
     101        return 1;
     102      }
     103  
     104    if (pthread_barrierattr_destroy (&ba) != 0)
     105      {
     106        puts ("barrierattr_destroy failed");
     107        return 1;
     108      }
     109  
     110    struct flock fl =
     111      {
     112        .l_type = F_WRLCK,
     113        .l_start = 0,
     114        .l_whence = SEEK_SET,
     115        .l_len = 10
     116      };
     117    if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0)
     118      {
     119        puts ("first fcntl failed");
     120        return 1;
     121      }
     122  
     123    pid_t pid = fork ();
     124    if (pid == -1)
     125      {
     126        puts ("fork failed");
     127        return 1;
     128      }
     129  
     130    if (pid == 0)
     131      {
     132        /* Make sure the child does not stay around indefinitely.  */
     133        alarm (10);
     134  
     135        /* Try to get the lock.  */
     136        if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLK, &fl)) == 0)
     137  	{
     138  	  puts ("child:  second flock succeeded");
     139  	  return 1;
     140  	}
     141      }
     142  
     143    pthread_barrier_wait (b);
     144  
     145    if (pid != 0)
     146      {
     147        fl.l_type = F_UNLCK;
     148        if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0)
     149  	{
     150  	  puts ("third fcntl failed");
     151  	  return 1;
     152  	}
     153      }
     154  
     155    pthread_barrier_wait (b);
     156  
     157    pthread_t th;
     158    if (pid == 0)
     159      {
     160        if (pthread_mutex_lock (&lock) != 0)
     161  	{
     162  	  puts ("1st locking of lock failed");
     163  	  return 1;
     164  	}
     165  
     166        if (pthread_mutex_lock (&lock2) != 0)
     167  	{
     168  	  puts ("1st locking of lock2 failed");
     169  	  return 1;
     170  	}
     171  
     172        if (pthread_create (&th, NULL, tf, NULL) != 0)
     173  	{
     174  	  puts ("pthread_create failed");
     175  	  return 1;
     176  	}
     177  
     178        if (pthread_mutex_lock (&lock) != 0)
     179  	{
     180  	  puts ("2nd locking of lock failed");
     181  	  return 1;
     182  	}
     183  
     184        puts ("child locked file");
     185      }
     186  
     187    pthread_barrier_wait (b);
     188  
     189    if (pid != 0)
     190      {
     191        fl.l_type = F_WRLCK;
     192        if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLK, &fl)) == 0)
     193  	{
     194  	  puts ("fifth fcntl succeeded");
     195  	  return 1;
     196  	}
     197  
     198        puts ("file locked by child");
     199      }
     200  
     201    pthread_barrier_wait (b);
     202  
     203    if (pid == 0)
     204      {
     205        if (pthread_mutex_unlock (&lock2) != 0)
     206  	{
     207  	  puts ("unlock of lock2 failed");
     208  	  return 1;
     209  	}
     210  
     211        if (pthread_join (th, NULL) != 0)
     212  	{
     213  	  puts ("join failed");
     214  	  return 1;
     215  	}
     216  
     217        puts ("child's thread terminated");
     218      }
     219  
     220    pthread_barrier_wait (b);
     221  
     222    if (pid != 0)
     223      {
     224        fl.l_type = F_WRLCK;
     225        if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLK, &fl)) == 0)
     226  	{
     227  	  puts ("fifth fcntl succeeded");
     228  	  return 1;
     229  	}
     230  
     231        puts ("file still locked");
     232      }
     233  
     234    pthread_barrier_wait (b);
     235  
     236    if (pid == 0)
     237      {
     238        _exit (0);
     239      }
     240  
     241    int status;
     242    if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
     243      {
     244        puts ("waitpid failed");
     245        return 1;
     246      }
     247    puts ("child terminated");
     248  
     249    if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0)
     250      {
     251        puts ("sixth fcntl failed");
     252        return 1;
     253      }
     254  
     255    return status;
     256  }
     257  
     258  #define TEST_FUNCTION do_test ()
     259  #include "../test-skeleton.c"