/* Copyright (C) 2003-2016 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 2003. 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 . */ #include #include #include #include #include #include #include #define N 4 #if __WORDSIZE == 64 #define GUARD_PATTERN 0xdeadbeafdeadbeaf #else #define GUARD_PATTERN 0xdeadbeaf #endif typedef struct { ucontext_t uctx; unsigned long guard[3]; } tst_context_t; static char stacks[N][2 * PTHREAD_STACK_MIN]; static tst_context_t ctx[N][2]; static volatile int failures; static void fct (long int n) { char on_stack[1]; /* Just to use the thread local descriptor. */ printf ("%ld: in %s now, on_stack = %p\n", n, __FUNCTION__, on_stack); errno = 0; if (ctx[n][1].uctx.uc_link != &ctx[n][0].uctx) { printf ("context[%ld][1] uc_link damaged, = %p\n", n, ctx[n][1].uctx.uc_link); exit (1); } if ((ctx[n][0].guard[0] != GUARD_PATTERN) || (ctx[n][0].guard[1] != GUARD_PATTERN) || (ctx[n][0].guard[2] != GUARD_PATTERN)) { printf ("%ld: %s context[0] overflow detected!\n", n, __FUNCTION__); ++failures; } if ((ctx[n][1].guard[0] != GUARD_PATTERN) || (ctx[n][1].guard[1] != GUARD_PATTERN) || (ctx[n][1].guard[2] != GUARD_PATTERN)) { printf ("%ld: %s context[1] overflow detected!\n", n, __FUNCTION__); ++failures; } if (n < 0 || n >= N) { printf ("%ld out of range\n", n); exit (1); } if (on_stack < stacks[n] || on_stack >= stacks[n] + sizeof (stacks[0])) { printf ("%ld: on_stack not on appropriate stack\n", n); exit (1); } } static void * tf (void *arg) { int n = (int) (long int) arg; ctx[n][0].guard[0] = GUARD_PATTERN; ctx[n][0].guard[1] = GUARD_PATTERN; ctx[n][0].guard[2] = GUARD_PATTERN; ctx[n][1].guard[0] = GUARD_PATTERN; ctx[n][1].guard[1] = GUARD_PATTERN; ctx[n][1].guard[2] = GUARD_PATTERN; if (getcontext (&ctx[n][1].uctx) != 0) { printf ("%d: cannot get context: %m\n", n); exit (1); } printf ("%d: %s: before makecontext\n", n, __FUNCTION__); ctx[n][1].uctx.uc_stack.ss_sp = stacks[n]; ctx[n][1].uctx.uc_stack.ss_size = sizeof (stacks[n]); ctx[n][1].uctx.uc_link = &ctx[n][0].uctx; makecontext (&ctx[n][1].uctx, (void (*) (void)) fct, 1, (long int) n); printf ("%d: %s: before swapcontext\n", n, __FUNCTION__); if (swapcontext (&ctx[n][0].uctx, &ctx[n][1].uctx) != 0) { ++failures; printf ("%d: %s: swapcontext failed\n", n, __FUNCTION__); } else printf ("%d: back in %s\n", n, __FUNCTION__); return NULL; } static volatile int global; static int do_test (void) { int n; pthread_t th[N]; ucontext_t mctx; puts ("making contexts"); if (getcontext (&mctx) != 0) { if (errno == ENOSYS) { puts ("context handling not supported"); exit (0); } printf ("%s: getcontext: %m\n", __FUNCTION__); exit (1); } /* Play some tricks with this context. */ if (++global == 1) if (setcontext (&mctx) != 0) { puts ("setcontext failed"); exit (1); } if (global != 2) { puts ("global not incremented twice"); exit (1); } puts ("global OK"); pthread_attr_t at; if (pthread_attr_init (&at) != 0) { puts ("attr_init failed"); return 1; } if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) { puts ("attr_setstacksize failed"); return 1; } for (n = 0; n < N; ++n) if (pthread_create (&th[n], &at, tf, (void *) (long int) n) != 0) { puts ("create failed"); exit (1); } if (pthread_attr_destroy (&at) != 0) { puts ("attr_destroy failed"); return 1; } for (n = 0; n < N; ++n) if (pthread_join (th[n], NULL) != 0) { puts ("join failed"); exit (1); } return failures; } #define TEST_FUNCTION do_test () #include "../test-skeleton.c"