1 | /* Verify that pthread_create does not deadlock when ctors take locks. |
2 | Copyright (C) 2021-2024 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library 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 the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <stdio.h> |
20 | #include <support/xdlfcn.h> |
21 | #include <support/xthread.h> |
22 | |
23 | /* |
24 | Check if ctor and pthread_create deadlocks in |
25 | |
26 | thread 1: dlopen -> ctor -> lock(user_lock) |
27 | thread 2: lock(user_lock) -> pthread_create |
28 | |
29 | or in |
30 | |
31 | thread 1: dlclose -> dtor -> lock(user_lock) |
32 | thread 2: lock(user_lock) -> pthread_create |
33 | */ |
34 | |
35 | static pthread_barrier_t bar_ctor; |
36 | static pthread_barrier_t bar_ctor_finish; |
37 | static pthread_barrier_t bar_dtor; |
38 | static pthread_mutex_t user_lock = PTHREAD_MUTEX_INITIALIZER; |
39 | |
40 | void |
41 | ctor (void) |
42 | { |
43 | xpthread_barrier_wait (barrier: &bar_ctor); |
44 | dprintf (1, "thread 1: in ctor: started.\n" ); |
45 | xpthread_mutex_lock (mutex: &user_lock); |
46 | dprintf (1, "thread 1: in ctor: locked user_lock.\n" ); |
47 | xpthread_mutex_unlock (mutex: &user_lock); |
48 | dprintf (1, "thread 1: in ctor: unlocked user_lock.\n" ); |
49 | dprintf (1, "thread 1: in ctor: done.\n" ); |
50 | xpthread_barrier_wait (barrier: &bar_ctor_finish); |
51 | } |
52 | |
53 | void |
54 | dtor (void) |
55 | { |
56 | xpthread_barrier_wait (barrier: &bar_dtor); |
57 | dprintf (1, "thread 1: in dtor: started.\n" ); |
58 | xpthread_mutex_lock (mutex: &user_lock); |
59 | dprintf (1, "thread 1: in dtor: locked user_lock.\n" ); |
60 | xpthread_mutex_unlock (mutex: &user_lock); |
61 | dprintf (1, "thread 1: in dtor: unlocked user_lock.\n" ); |
62 | dprintf (1, "thread 1: in dtor: done.\n" ); |
63 | } |
64 | |
65 | static void * |
66 | thread3 (void *a) |
67 | { |
68 | dprintf (1, "thread 3: started.\n" ); |
69 | dprintf (1, "thread 3: done.\n" ); |
70 | return 0; |
71 | } |
72 | |
73 | static void * |
74 | thread2 (void *a) |
75 | { |
76 | pthread_t t3; |
77 | dprintf (1, "thread 2: started.\n" ); |
78 | |
79 | xpthread_mutex_lock (mutex: &user_lock); |
80 | dprintf (1, "thread 2: locked user_lock.\n" ); |
81 | xpthread_barrier_wait (barrier: &bar_ctor); |
82 | t3 = xpthread_create (attr: 0, thread_func: thread3, closure: 0); |
83 | xpthread_mutex_unlock (mutex: &user_lock); |
84 | dprintf (1, "thread 2: unlocked user_lock.\n" ); |
85 | xpthread_join (thr: t3); |
86 | xpthread_barrier_wait (barrier: &bar_ctor_finish); |
87 | |
88 | xpthread_mutex_lock (mutex: &user_lock); |
89 | dprintf (1, "thread 2: locked user_lock.\n" ); |
90 | xpthread_barrier_wait (barrier: &bar_dtor); |
91 | t3 = xpthread_create (attr: 0, thread_func: thread3, closure: 0); |
92 | xpthread_mutex_unlock (mutex: &user_lock); |
93 | dprintf (1, "thread 2: unlocked user_lock.\n" ); |
94 | xpthread_join (thr: t3); |
95 | |
96 | dprintf (1, "thread 2: done.\n" ); |
97 | return 0; |
98 | } |
99 | |
100 | static void |
101 | thread1 (void) |
102 | { |
103 | dprintf (1, "thread 1: started.\n" ); |
104 | xpthread_barrier_init (barrier: &bar_ctor, NULL, count: 2); |
105 | xpthread_barrier_init (barrier: &bar_ctor_finish, NULL, count: 2); |
106 | xpthread_barrier_init (barrier: &bar_dtor, NULL, count: 2); |
107 | pthread_t t2 = xpthread_create (attr: 0, thread_func: thread2, closure: 0); |
108 | void *p = xdlopen (filename: "tst-create1mod.so" , RTLD_NOW | RTLD_GLOBAL); |
109 | dprintf (1, "thread 1: dlopen done.\n" ); |
110 | xdlclose (handle: p); |
111 | dprintf (1, "thread 1: dlclose done.\n" ); |
112 | xpthread_join (thr: t2); |
113 | dprintf (1, "thread 1: done.\n" ); |
114 | } |
115 | |
116 | static int |
117 | do_test (void) |
118 | { |
119 | thread1 (); |
120 | return 0; |
121 | } |
122 | |
123 | #include <support/test-driver.c> |
124 | |