(root)/
glibc-2.38/
nptl/
tst-context1.c
       1  /* Copyright (C) 2003-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 <error.h>
      20  #include <limits.h>
      21  #include <pthread.h>
      22  #include <stdio.h>
      23  #include <stdlib.h>
      24  #include <ucontext.h>
      25  #include <support/support.h>
      26  
      27  #define N	4
      28  #if __WORDSIZE == 64
      29  #define GUARD_PATTERN 0xdeadbeafdeadbeaf
      30  #else
      31  #define GUARD_PATTERN 0xdeadbeaf
      32  #endif
      33  
      34  typedef struct {
      35         ucontext_t uctx;
      36         unsigned long	guard[3];
      37     } tst_context_t;
      38  
      39  static char *stacks[N];
      40  static size_t stack_size;
      41  static tst_context_t ctx[N][2];
      42  static volatile int failures;
      43  
      44  
      45  static void
      46  fct (long int n)
      47  {
      48    char on_stack[1];
      49  
      50    /* Just to use the thread local descriptor.  */
      51    printf ("%ld: in %s now, on_stack = %p\n", n, __FUNCTION__, on_stack);
      52    errno = 0;
      53  
      54    if (ctx[n][1].uctx.uc_link != &ctx[n][0].uctx)
      55      {
      56        printf ("context[%ld][1] uc_link damaged, = %p\n", n,
      57  	      ctx[n][1].uctx.uc_link);
      58        exit (1);
      59      }
      60  
      61    if ((ctx[n][0].guard[0] != GUARD_PATTERN)
      62    ||  (ctx[n][0].guard[1] != GUARD_PATTERN)
      63    ||  (ctx[n][0].guard[2] != GUARD_PATTERN))
      64      {
      65        printf ("%ld: %s context[0] overflow detected!\n", n, __FUNCTION__);
      66        ++failures;
      67      }
      68  
      69    if ((ctx[n][1].guard[0] != GUARD_PATTERN)
      70    ||  (ctx[n][1].guard[1] != GUARD_PATTERN)
      71    ||  (ctx[n][1].guard[2] != GUARD_PATTERN))
      72      {
      73        printf ("%ld: %s context[1] overflow detected!\n", n, __FUNCTION__);
      74        ++failures;
      75      }
      76  
      77    if (n < 0 || n >= N)
      78      {
      79        printf ("%ld out of range\n", n);
      80        exit (1);
      81      }
      82  
      83    if (on_stack < stacks[n] || on_stack >= stacks[n] + stack_size)
      84      {
      85        printf ("%ld: on_stack not on appropriate stack\n", n);
      86        exit (1);
      87      }
      88  }
      89  
      90  
      91  static void *
      92  tf (void *arg)
      93  {
      94    int n = (int) (long int) arg;
      95  
      96    ctx[n][0].guard[0] = GUARD_PATTERN;
      97    ctx[n][0].guard[1] = GUARD_PATTERN;
      98    ctx[n][0].guard[2] = GUARD_PATTERN;
      99  
     100    ctx[n][1].guard[0] = GUARD_PATTERN;
     101    ctx[n][1].guard[1] = GUARD_PATTERN;
     102    ctx[n][1].guard[2] = GUARD_PATTERN;
     103  
     104    if (getcontext (&ctx[n][1].uctx) != 0)
     105      {
     106        printf ("%d: cannot get context: %m\n", n);
     107        exit (1);
     108      }
     109  
     110    printf ("%d: %s: before makecontext\n", n, __FUNCTION__);
     111  
     112    ctx[n][1].uctx.uc_stack.ss_sp = stacks[n];
     113    ctx[n][1].uctx.uc_stack.ss_size = stack_size;
     114    ctx[n][1].uctx.uc_link = &ctx[n][0].uctx;
     115    makecontext (&ctx[n][1].uctx, (void (*) (void)) fct, 1, (long int) n);
     116  
     117    printf ("%d: %s: before swapcontext\n", n, __FUNCTION__);
     118  
     119    if (swapcontext (&ctx[n][0].uctx, &ctx[n][1].uctx) != 0)
     120      {
     121        ++failures;
     122        printf ("%d: %s: swapcontext failed\n", n, __FUNCTION__);
     123      }
     124    else
     125      printf ("%d: back in %s\n", n, __FUNCTION__);
     126  
     127    return NULL;
     128  }
     129  
     130  
     131  static volatile int global;
     132  
     133  
     134  static int
     135  do_test (void)
     136  {
     137    int n;
     138    pthread_t th[N];
     139    ucontext_t mctx;
     140  
     141    stack_size = 2 * PTHREAD_STACK_MIN;
     142    for (int i = 0; i < N; i++)
     143      stacks[i] = xmalloc (stack_size);
     144  
     145    puts ("making contexts");
     146    if (getcontext (&mctx) != 0)
     147      {
     148        if (errno == ENOSYS)
     149  	{
     150  	  puts ("context handling not supported");
     151  	  exit (0);
     152  	}
     153  
     154        printf ("%s: getcontext: %m\n", __FUNCTION__);
     155        exit (1);
     156      }
     157  
     158    /* Play some tricks with this context.  */
     159    if (++global == 1)
     160      if (setcontext (&mctx) != 0)
     161        {
     162  	puts ("setcontext failed");
     163  	exit (1);
     164        }
     165    if (global != 2)
     166      {
     167        puts ("global not incremented twice");
     168        exit (1);
     169      }
     170    puts ("global OK");
     171  
     172    pthread_attr_t at;
     173  
     174    if (pthread_attr_init (&at) != 0)
     175      {
     176        puts ("attr_init failed");
     177        return 1;
     178      }
     179  
     180    if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0)
     181      {
     182        puts ("attr_setstacksize failed");
     183        return 1;
     184      }
     185  
     186    for (n = 0; n < N; ++n)
     187      if (pthread_create (&th[n], &at, tf, (void *) (long int) n) != 0)
     188        {
     189  	puts ("create failed");
     190  	exit (1);
     191        }
     192  
     193    if (pthread_attr_destroy (&at) != 0)
     194      {
     195        puts ("attr_destroy failed");
     196        return 1;
     197      }
     198  
     199    for (n = 0; n < N; ++n)
     200      if (pthread_join (th[n], NULL) != 0)
     201        {
     202  	puts ("join failed");
     203  	exit (1);
     204        }
     205  
     206    for (int i = 0; i < N; i++)
     207      free (stacks[i]);
     208  
     209    return failures;
     210  }
     211  
     212  #define TEST_FUNCTION do_test ()
     213  #include "../test-skeleton.c"