| /* | |
| * Copyright 2012 Red Hat, Inc. | |
| * | |
| * SPDX-License-Identifier: LGPL-2.1-or-later | |
| * | |
| * This program is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * See the included COPYING file for more information. | |
| */ | |
| #include <glib-object.h> | |
| gboolean fail; | |
| #define THREADS 10 | |
| #define ROUNDS 10000 | |
| GObject *object; | |
| gint bucket[THREADS]; /* accessed from multiple threads, but should never be contested due to the sequence of thread operations */ | |
| static gpointer | |
| thread_func (gpointer data) | |
| { | |
| gint idx = GPOINTER_TO_INT (data); | |
| gint i; | |
| gint d; | |
| gint value; | |
| gint new_value; | |
| for (i = 0; i < ROUNDS; i++) | |
| { | |
| d = g_random_int_range (-10, 100); | |
| bucket[idx] += d; | |
| retry: | |
| value = GPOINTER_TO_INT (g_object_get_data (object, "test")); | |
| new_value = value + d; | |
| if (fail) | |
| g_object_set_data (object, "test", GINT_TO_POINTER (new_value)); | |
| else | |
| { | |
| if (!g_object_replace_data (object, "test", | |
| GINT_TO_POINTER (value), | |
| GINT_TO_POINTER (new_value), | |
| NULL, NULL)) | |
| goto retry; | |
| } | |
| g_thread_yield (); | |
| } | |
| return NULL; | |
| } | |
| static void | |
| test_qdata_threaded (void) | |
| { | |
| gint sum; | |
| gint i; | |
| GThread *threads[THREADS]; | |
| gint result; | |
| object = g_object_new (G_TYPE_OBJECT, NULL); | |
| g_object_set_data (object, "test", GINT_TO_POINTER (0)); | |
| for (i = 0; i < THREADS; i++) | |
| bucket[i] = 0; | |
| for (i = 0; i < THREADS; i++) | |
| threads[i] = g_thread_new ("qdata", thread_func, GINT_TO_POINTER (i)); | |
| for (i = 0; i < THREADS; i++) | |
| g_thread_join (threads[i]); | |
| sum = 0; | |
| for (i = 0; i < THREADS; i++) | |
| sum += bucket[i]; | |
| result = GPOINTER_TO_INT (g_object_get_data (object, "test")); | |
| g_assert_cmpint (sum, ==, result); | |
| g_object_unref (object); | |
| } | |
| static void | |
| test_qdata_dup (void) | |
| { | |
| gchar *s, *s2; | |
| GQuark quark; | |
| gboolean b; | |
| quark = g_quark_from_static_string ("test"); | |
| object = g_object_new (G_TYPE_OBJECT, NULL); | |
| s = g_strdup ("s"); | |
| g_object_set_qdata_full (object, quark, s, g_free); | |
| s2 = g_object_dup_qdata (object, quark, (GDuplicateFunc)g_strdup, NULL); | |
| g_assert_cmpstr (s, ==, s2); | |
| g_assert (s != s2); | |
| g_free (s2); | |
| b = g_object_replace_qdata (object, quark, s, "s2", NULL, NULL); | |
| g_assert (b); | |
| g_free (s); | |
| g_object_unref (object); | |
| } | |
| int | |
| main (int argc, char **argv) | |
| { | |
| g_test_init (&argc, &argv, NULL); | |
| fail = !!g_getenv ("FAIL"); | |
| g_test_add_func ("/qdata/threaded", test_qdata_threaded); | |
| g_test_add_func ("/qdata/dup", test_qdata_dup); | |
| return g_test_run (); | |
| } |