1 | /* Unit tests for GThreadPool |
2 | * Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com> |
3 | * |
4 | * This work is provided "as is"; redistribution and modification |
5 | * in whole or in part, in any medium, physical or electronic is |
6 | * permitted without restriction. |
7 | * |
8 | * This work is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
11 | * |
12 | * In no event shall the authors or contributors be liable for any |
13 | * direct, indirect, incidental, special, exemplary, or consequential |
14 | * damages (including, but not limited to, procurement of substitute |
15 | * goods or services; loss of use, data, or profits; or business |
16 | * interruption) however caused and on any theory of liability, whether |
17 | * in contract, strict liability, or tort (including negligence or |
18 | * otherwise) arising in any way out of the use of this software, even |
19 | * if advised of the possibility of such damage. |
20 | */ |
21 | |
22 | #include <config.h> |
23 | |
24 | #include <glib.h> |
25 | |
26 | typedef struct { |
27 | GMutex mutex; |
28 | GCond cond; |
29 | gboolean signalled; |
30 | } MutexCond; |
31 | |
32 | static void |
33 | pool_func (gpointer data, gpointer user_data) |
34 | { |
35 | MutexCond *m = user_data; |
36 | |
37 | g_mutex_lock (mutex: &m->mutex); |
38 | g_assert_false (m->signalled); |
39 | g_assert_true (data == GUINT_TO_POINTER (123)); |
40 | m->signalled = TRUE; |
41 | g_cond_signal (cond: &m->cond); |
42 | g_mutex_unlock (mutex: &m->mutex); |
43 | } |
44 | |
45 | static void |
46 | test_simple (gconstpointer shared) |
47 | { |
48 | GThreadPool *pool; |
49 | GError *err = NULL; |
50 | MutexCond m; |
51 | gboolean success; |
52 | |
53 | g_mutex_init (mutex: &m.mutex); |
54 | g_cond_init (cond: &m.cond); |
55 | |
56 | if (GPOINTER_TO_INT (shared)) |
57 | { |
58 | g_test_summary (summary: "Tests that a shared, non-exclusive thread pool " |
59 | "generally works." ); |
60 | pool = g_thread_pool_new (func: pool_func, user_data: &m, max_threads: -1, FALSE, error: &err); |
61 | } |
62 | else |
63 | { |
64 | g_test_summary (summary: "Tests that an exclusive thread pool generally works." ); |
65 | pool = g_thread_pool_new (func: pool_func, user_data: &m, max_threads: 2, TRUE, error: &err); |
66 | } |
67 | g_assert_no_error (err); |
68 | g_assert_nonnull (pool); |
69 | |
70 | g_mutex_lock (mutex: &m.mutex); |
71 | m.signalled = FALSE; |
72 | |
73 | success = g_thread_pool_push (pool, GUINT_TO_POINTER (123), error: &err); |
74 | g_assert_no_error (err); |
75 | g_assert_true (success); |
76 | |
77 | while (!m.signalled) |
78 | g_cond_wait (cond: &m.cond, mutex: &m.mutex); |
79 | g_mutex_unlock (mutex: &m.mutex); |
80 | |
81 | g_thread_pool_free (pool, TRUE, TRUE); |
82 | } |
83 | |
84 | static void |
85 | dummy_pool_func (gpointer data, gpointer user_data) |
86 | { |
87 | g_assert_true (data == GUINT_TO_POINTER (123)); |
88 | } |
89 | |
90 | static void |
91 | test_create_first_pool (gconstpointer shared_first) |
92 | { |
93 | GThreadPool *pool; |
94 | GError *err = NULL; |
95 | gboolean success; |
96 | |
97 | g_test_bug (bug_uri_snippet: "https://gitlab.gnome.org/GNOME/glib/issues/2012" ); |
98 | if (GPOINTER_TO_INT (shared_first)) |
99 | { |
100 | g_test_summary (summary: "Tests that creating an exclusive pool after a " |
101 | "shared one works." ); |
102 | } |
103 | else |
104 | { |
105 | g_test_summary (summary: "Tests that creating a shared pool after an " |
106 | "exclusive one works." ); |
107 | } |
108 | |
109 | if (!g_test_subprocess ()) |
110 | { |
111 | g_test_trap_subprocess (NULL, usec_timeout: 0, test_flags: 0); |
112 | g_test_trap_assert_passed (); |
113 | return; |
114 | } |
115 | |
116 | g_thread_pool_set_max_unused_threads (max_threads: 0); |
117 | |
118 | if (GPOINTER_TO_INT (shared_first)) |
119 | pool = g_thread_pool_new (func: dummy_pool_func, NULL, max_threads: -1, FALSE, error: &err); |
120 | else |
121 | pool = g_thread_pool_new (func: dummy_pool_func, NULL, max_threads: 2, TRUE, error: &err); |
122 | g_assert_no_error (err); |
123 | g_assert_nonnull (pool); |
124 | |
125 | success = g_thread_pool_push (pool, GUINT_TO_POINTER (123), error: &err); |
126 | g_assert_no_error (err); |
127 | g_assert_true (success); |
128 | |
129 | g_thread_pool_free (pool, TRUE, TRUE); |
130 | |
131 | if (GPOINTER_TO_INT (shared_first)) |
132 | pool = g_thread_pool_new (func: dummy_pool_func, NULL, max_threads: 2, TRUE, error: &err); |
133 | else |
134 | pool = g_thread_pool_new (func: dummy_pool_func, NULL, max_threads: -1, FALSE, error: &err); |
135 | g_assert_no_error (err); |
136 | g_assert_nonnull (pool); |
137 | |
138 | success = g_thread_pool_push (pool, GUINT_TO_POINTER (123), error: &err); |
139 | g_assert_no_error (err); |
140 | g_assert_true (success); |
141 | |
142 | g_thread_pool_free (pool, TRUE, TRUE); |
143 | } |
144 | |
145 | int |
146 | main (int argc, char *argv[]) |
147 | { |
148 | g_test_init (argc: &argc, argv: &argv, NULL); |
149 | |
150 | g_test_add_data_func (testpath: "/thread_pool/shared" , GINT_TO_POINTER (TRUE), test_func: test_simple); |
151 | g_test_add_data_func (testpath: "/thread_pool/exclusive" , GINT_TO_POINTER (FALSE), test_func: test_simple); |
152 | g_test_add_data_func (testpath: "/thread_pool/create_shared_after_exclusive" , GINT_TO_POINTER (FALSE), test_func: test_create_first_pool); |
153 | g_test_add_data_func (testpath: "/thread_pool/create_exclusive_after_shared" , GINT_TO_POINTER (TRUE), test_func: test_create_first_pool); |
154 | |
155 | return g_test_run (); |
156 | } |
157 | |