1 /* 2 * Copyright (C) 2015 Cyril Hrubis <chrubis (at) suse.cz> 3 * 4 * Licensed under the GNU GPLv2 or later. 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 /* 20 * Block several threads on a private mutex, then wake them up. 21 */ 22 23 #include <errno.h> 24 #include <pthread.h> 25 26 #include "test.h" 27 #include "safe_macros.h" 28 #include "futextest.h" 29 #include "futex_utils.h" 30 31 const char *TCID="futex_wake02"; 32 const int TST_TOTAL=11; 33 34 static futex_t futex = FUTEX_INITIALIZER; 35 36 static volatile int threads_flags[55]; 37 38 static int threads_awake(void) 39 { 40 int ret = 0; 41 unsigned int i; 42 43 for (i = 0; i < ARRAY_SIZE(threads_flags); i++) { 44 if (threads_flags[i]) 45 ret++; 46 } 47 48 return ret; 49 } 50 51 static void clear_threads_awake(void) 52 { 53 unsigned int i; 54 55 for (i = 0; i < ARRAY_SIZE(threads_flags); i++) 56 threads_flags[i] = 0; 57 } 58 59 static void *threaded(void *arg) 60 { 61 long i = (long)arg; 62 63 futex_wait(&futex, futex, NULL, FUTEX_PRIVATE_FLAG); 64 65 threads_flags[i] = 1; 66 67 return NULL; 68 } 69 70 static void do_child(void) 71 { 72 int res, i, j, awake; 73 pthread_t t[55]; 74 75 for (i = 0; i < (int)ARRAY_SIZE(t); i++) { 76 res = pthread_create(&t[i], NULL, threaded, (void*)((long)i)); 77 if (res) { 78 tst_brkm(TBROK, NULL, "pthread_create(): %s", 79 tst_strerrno(res)); 80 } 81 } 82 83 while (wait_for_threads(ARRAY_SIZE(t))) 84 usleep(100); 85 86 for (i = 1; i <= 10; i++) { 87 clear_threads_awake(); 88 res = futex_wake(&futex, i, FUTEX_PRIVATE_FLAG); 89 if (i != res) { 90 tst_resm(TFAIL, 91 "futex_wake() woken up %i threads, expected %i", 92 res, i); 93 } 94 95 for (j = 0; j < 100000; j++) { 96 awake = threads_awake(); 97 if (awake == i) 98 break; 99 100 usleep(100); 101 } 102 103 if (awake == i) { 104 tst_resm(TPASS, "futex_wake() woken up %i threads", i); 105 } else { 106 tst_resm(TFAIL, "Woken up %i threads, expected %i", 107 awake, i); 108 } 109 } 110 111 res = futex_wake(&futex, 1, FUTEX_PRIVATE_FLAG); 112 113 if (res) { 114 tst_resm(TFAIL, "futex_wake() woken up %i, none were waiting", 115 res); 116 } else { 117 tst_resm(TPASS, "futex_wake() woken up 0 threads"); 118 } 119 120 for (i = 0; i < (int)ARRAY_SIZE(t); i++) 121 pthread_join(t[i], NULL); 122 123 tst_exit(); 124 } 125 126 /* 127 * We do the real test in a child because with the test -i parameter the loop 128 * that checks that all threads are sleeping may fail with ENOENT. That is 129 * because some of the threads from previous run may still be there. 130 * 131 * Which is because the userspace part of pthread_join() sleeps in a futex on a 132 * pthread tid which is woken up at the end of the exit_mm(tsk) which is before 133 * the process is removed from the parent thread_group list. So there is a 134 * small race window where the readdir() returns the process tid as a directory 135 * under /proc/$PID/tasks/, but the subsequent open() fails with ENOENT because 136 * the thread was removed meanwhile. 137 */ 138 static void verify_futex_wake(void) 139 { 140 int pid; 141 142 pid = tst_fork(); 143 144 switch (pid) { 145 case 0: 146 do_child(); 147 case -1: 148 tst_brkm(TBROK | TERRNO, NULL, "fork() failed"); 149 default: 150 tst_record_childstatus(NULL, pid); 151 } 152 } 153 154 int main(int argc, char *argv[]) 155 { 156 int lc; 157 158 tst_parse_opts(argc, argv, NULL, NULL); 159 160 for (lc = 0; TEST_LOOPING(lc); lc++) 161 verify_futex_wake(); 162 163 tst_exit(); 164 } 165