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 #include "common.h" 23 24 #define NTHREADS 10 25 #define DBNAME "testdb" 26 #define DBDIR "." 27 28 #define DEBUG_PRINT 29 #undef DEBUG_PRINT 30 31 /* 32 * tests 33 */ 34 typedef gboolean (*TestFunc) (GError **); 35 static gboolean test1 (GError **error); 36 37 TestFunc tests[] = { 38 test1, 39 }; 40 41 int 42 main (int argc, char** argv) 43 { 44 gchar *fname; 45 GError *error = NULL; 46 47 #if GLIB_CHECK_VERSION(2,36,0) 48 #else 49 g_type_init (); 50 #endif 51 gda_init (); 52 53 /* set up the test database */ 54 fname = g_build_filename (ROOT_DIR, "tests", "multi-threading", "testdb.sql", NULL); 55 if (!create_sqlite_db (DBDIR, DBNAME, fname, &error)) { 56 g_print ("Cannot create test database: %s\n", error && error->message ? 57 error->message : "no detail"); 58 return 1; 59 } 60 g_free (fname); 61 62 guint failures = 0; 63 guint j, ntests = 0;; 64 for (j = 0; j < 500; j++) { 65 guint i; 66 67 #ifdef DEBUG_PRINT 68 g_print ("================================================== test %d\n", j); 69 #else 70 g_print ("."); 71 fflush (stdout); 72 #endif 73 for (i = 0; i < sizeof (tests) / sizeof (TestFunc); i++) { 74 GError *error = NULL; 75 if (! tests[i] (&error)) { 76 g_print ("Test %d failed: %s\n", i+1, 77 error && error->message ? error->message : "No detail"); 78 if (error) 79 g_error_free (error); 80 failures ++; 81 } 82 ntests ++; 83 } 84 } 85 86 g_print ("\nTESTS COUNT: %d\n", ntests); 87 g_print ("FAILURES: %d\n", failures); 88 89 return failures != 0 ? 1 : 0; 90 } 91 92 typedef struct _ThData { 93 GMutex *start_lock; 94 GThread *thread; 95 GdaConnection *cnc; 96 gint th_id; 97 gboolean error; 98 } ThData; 99 100 static gboolean 101 test_multiple_threads (GThreadFunc func, GError **error) 102 { 103 ThData data[NTHREADS]; 104 gint i; 105 GdaConnection *cnc = NULL; 106 107 /* open cnc */ 108 gchar *cnc_string; 109 gchar *edir, *edbname; 110 111 edir = gda_rfc1738_encode (DBDIR); 112 edbname = gda_rfc1738_encode (DBNAME); 113 cnc_string = g_strdup_printf ("DB_DIR=%s;DB_NAME=%s", edir, edbname); 114 g_free (edir); 115 g_free (edbname); 116 cnc = gda_connection_open_from_string ("SQLite", cnc_string, NULL, 117 GDA_CONNECTION_OPTIONS_NONE, NULL); 118 g_free (cnc_string); 119 120 if (!cnc) 121 return FALSE; 122 g_object_set (G_OBJECT (cnc), "thread-owner", g_thread_self (), NULL); 123 124 /* prepare threads data */ 125 for (i = 0; i < NTHREADS; i++) { 126 ThData *d = &(data[i]); 127 d->start_lock = g_mutex_new (); 128 g_mutex_lock (d->start_lock); 129 d->thread = NULL; 130 d->cnc = cnc; 131 d->th_id = i; 132 d->error = FALSE; 133 } 134 135 /* start all the threads, they will lock on d->start_lock */ 136 for (i = 0; i < NTHREADS; i++) { 137 ThData *d = &(data[i]); 138 #ifdef DEBUG_PRINT 139 g_print ("Running thread %d\n", d->th_id); 140 #endif 141 d->thread = g_thread_create (func, d, TRUE, NULL); 142 #ifdef DEBUG_PRINT 143 g_print ("Running thread %d has pointer %p\n", d->th_id, d->thread); 144 #endif 145 } 146 147 /* unlock all the threads */ 148 for (i = 0; i < NTHREADS; i++) { 149 ThData *d = &(data[i]); 150 g_mutex_unlock (d->start_lock); 151 } 152 153 gboolean retval = TRUE; 154 for (i = 0; i < NTHREADS; i++) { 155 ThData *d = &(data[i]); 156 g_object_set (G_OBJECT (cnc), "thread-owner", d->thread, NULL); 157 g_thread_join (d->thread); 158 if (d->error) 159 retval = FALSE; 160 } 161 162 for (i = 0; i < NTHREADS; i++) { 163 ThData *d = &(data[i]); 164 g_mutex_free (d->start_lock); 165 } 166 167 g_object_unref (cnc); 168 169 return retval; 170 } 171 172 /* 173 * Run SELECT on the same connection 174 */ 175 gpointer 176 test1_start_thread (ThData *data) 177 { 178 /* initially start locked */ 179 g_mutex_lock (data->start_lock); 180 g_mutex_unlock (data->start_lock); 181 182 /* threads use @cnc */ 183 if (gda_lockable_trylock ((GdaLockable*) data->cnc)) { 184 #ifdef DEBUG_PRINT 185 g_print ("Th %d has tried to lock cnc and succeeded\n", data->th_id); 186 #endif 187 } 188 else { 189 #ifdef DEBUG_PRINT 190 g_print ("Th %d has tried to lock cnc and failed, locking it (may block)...\n", data->th_id); 191 #endif 192 gda_lockable_lock ((GdaLockable*) data->cnc); 193 } 194 gda_lockable_unlock ((GdaLockable*) data->cnc); 195 #ifdef DEBUG_PRINT 196 g_print ("Th %d has unlocked cnc\n", data->th_id); 197 #endif 198 199 gda_lockable_lock ((GdaLockable*) data->cnc); 200 #ifdef DEBUG_PRINT 201 g_print ("Th %d has locked cnc\n", data->th_id); 202 #endif 203 204 g_thread_yield (); 205 206 gda_lockable_lock ((GdaLockable*) data->cnc); 207 #ifdef DEBUG_PRINT 208 g_print ("Th %d has re-locked cnc\n", data->th_id); 209 #endif 210 g_thread_yield (); 211 212 gda_lockable_unlock ((GdaLockable*) data->cnc); 213 #ifdef DEBUG_PRINT 214 g_print ("Th %d has unlocked cnc\n", data->th_id); 215 #endif 216 g_thread_yield (); 217 218 gda_lockable_unlock ((GdaLockable*) data->cnc); 219 #ifdef DEBUG_PRINT 220 g_print ("Th %d has re-unlocked cnc\n", data->th_id); 221 #endif 222 g_thread_yield (); 223 224 225 #ifdef DEBUG_PRINT 226 g_print ("Th %d finished\n", data->th_id); 227 #endif 228 return NULL; 229 } 230 231 static gboolean 232 test1 (GError **error) 233 { 234 return test_multiple_threads ((GThreadFunc) test1_start_thread, error); 235 } 236