1 /*
2  * Copyright (C) 2008 - 2011 Vivien Malerba <malerba@gnome-db.org>
3  * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (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 the
13  * 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 #include <libgda/libgda.h>
20 #include <string.h>
21 #include <unistd.h>
22 
23 #define NTHREADS 3
24 #define DEBUG_PRINT
25 #undef DEBUG_PRINT
26 
27 
28 /*
29  * tests
30  */
31 typedef gboolean (*TestFunc) (GError **);
32 static gboolean test1 (GError **error);
33 static gboolean test2 (GError **error);
34 static gboolean test3 (GError **error);
35 
36 TestFunc tests[] = {
37 	test1,
38 	test2,
39 	test3
40 };
41 
42 int
main(int argc,char ** argv)43 main (int argc, char** argv)
44 {
45 #if GLIB_CHECK_VERSION(2,36,0)
46 #else
47 	g_type_init ();
48 #endif
49 	gda_init ();
50 
51 	gint failures = 0;
52 	gint j, ntests = 0;;
53 	for (j = 0; j < 10; j++) {
54 		guint i;
55 
56 		for (i = 0; i < sizeof (tests) / sizeof (TestFunc); i++) {
57 			GError *error = NULL;
58 			if (! tests[i] (&error)) {
59 				g_print ("Test %d failed: %s\n", i+1,
60 					 error && error->message ? error->message : "No detail");
61 				if (error)
62 					g_error_free (error);
63 				failures ++;
64 			}
65 			ntests ++;
66 		}
67 	}
68 
69 	g_print ("TESTS COUNT: %d\n", ntests);
70 	g_print ("FAILURES: %d\n", failures);
71 
72 	return failures != 0 ? 1 : 0;
73 }
74 
75 typedef struct {
76 	GThread  *thread;
77 	gint      th_id;
78 	gboolean  finished;
79 	GdaMutex *mutex;
80 } ThData;
81 
82 static gboolean
test_multiple_threads(GThreadFunc func,GError ** error)83 test_multiple_threads (GThreadFunc func, GError **error)
84 {
85 	GdaMutex *mutex;
86 	ThData data[NTHREADS];
87 	gint i;
88 
89 	mutex = gda_mutex_new ();
90 
91 	for (i = 0; i < NTHREADS; i++) {
92 		ThData *d = &(data[i]);
93 		d->th_id = i;
94 		d->mutex = mutex;
95 		d->finished = FALSE;
96 	}
97 
98 	for (i = 0; i < NTHREADS; i++) {
99 		ThData *d = &(data[i]);
100 #ifdef DEBUG_PRINT
101 		g_print ("Running thread %d\n", d->th_id);
102 #endif
103 		d->thread = g_thread_create (func, d, TRUE, NULL);
104 	}
105 
106 	/* wait a bit */
107 	usleep (100000);
108 
109 	for (i = 0; i < NTHREADS; i++) {
110 		ThData *d = &(data[i]);
111 		if (!d->finished) {
112 			/* there are some threads locked somethere */
113 			exit (EXIT_FAILURE);
114 		}
115 		else
116 			g_thread_join (d->thread);
117 	}
118 
119 	gda_mutex_free (mutex);
120 
121 	return TRUE;
122 }
123 
124 /*
125  * Creation and destruction test
126  */
127 static gboolean
test1(GError ** error)128 test1 (GError **error)
129 {
130 	GdaMutex *mutex;
131 
132 	mutex = gda_mutex_new ();
133 	gda_mutex_free (mutex);
134 
135 	return TRUE;
136 }
137 
138 /*
139  * Twice locking
140  */
141 gpointer
test2_start_thread(ThData * data)142 test2_start_thread (ThData *data)
143 {
144 	gda_mutex_lock (data->mutex);
145 #ifdef DEBUG_PRINT
146 	g_print ("Mutex locked for %d\n", data->th_id);
147 #endif
148 	g_thread_yield ();
149 	gda_mutex_lock (data->mutex);
150 #ifdef DEBUG_PRINT
151 	g_print ("Mutex re-locked for %d\n", data->th_id);
152 #endif
153 	gda_mutex_unlock (data->mutex);
154 #ifdef DEBUG_PRINT
155 	g_print ("Mutex unlocked for %d\n", data->th_id);
156 	g_print ("Mutex unlocked for %d\n", data->th_id);
157 #endif
158 	gda_mutex_unlock (data->mutex);
159 	data->finished = TRUE;
160 	return NULL;
161 }
162 
163 static gboolean
test2(GError ** error)164 test2 (GError **error)
165 {
166 	return test_multiple_threads ((GThreadFunc) test2_start_thread, error);
167 }
168 
169 /*
170  * Try lock
171  */
172 gpointer
test3_start_thread(ThData * data)173 test3_start_thread (ThData *data)
174 {
175 	gboolean tried = FALSE;
176 	while (!tried) {
177 		tried = gda_mutex_trylock (data->mutex);
178 #ifdef DEBUG_PRINT
179 		g_print ("TRY for %d: %s\n", data->th_id, tried ? "got it" : "no luck");
180 #endif
181 		g_thread_yield ();
182 	}
183 #ifdef DEBUG_PRINT
184 	g_print ("Mutex locked for %d\n", data->th_id);
185 #endif
186 	g_thread_yield ();
187 	gda_mutex_lock (data->mutex);
188 #ifdef DEBUG_PRINT
189 	g_print ("Mutex re-locked for %d\n", data->th_id);
190 #endif
191 	gda_mutex_unlock (data->mutex);
192 #ifdef DEBUG_PRINT
193 	g_print ("Mutex unlocked for %d\n", data->th_id);
194 	g_print ("Mutex unlocked for %d\n", data->th_id);
195 #endif
196 	gda_mutex_unlock (data->mutex);
197 	data->finished = TRUE;
198 	return NULL;
199 }
200 
201 static gboolean
test3(GError ** error)202 test3 (GError **error)
203 {
204 	return test_multiple_threads ((GThreadFunc) test3_start_thread, error);
205 }
206