1#include <unistd.h>
2#include <glib.h>
3#include <glib-object.h>
4
5#define G_TYPE_TEST               (my_test_get_type ())
6#define MY_TEST(test)              (G_TYPE_CHECK_INSTANCE_CAST ((test), G_TYPE_TEST, GTest))
7#define MY_IS_TEST(test)           (G_TYPE_CHECK_INSTANCE_TYPE ((test), G_TYPE_TEST))
8#define MY_TEST_CLASS(tclass)      (G_TYPE_CHECK_CLASS_CAST ((tclass), G_TYPE_TEST, GTestClass))
9#define MY_IS_TEST_CLASS(tclass)   (G_TYPE_CHECK_CLASS_TYPE ((tclass), G_TYPE_TEST))
10#define MY_TEST_GET_CLASS(test)    (G_TYPE_INSTANCE_GET_CLASS ((test), G_TYPE_TEST, GTestClass))
11
12typedef struct _GTest GTest;
13typedef struct _GTestClass GTestClass;
14
15struct _GTest
16{
17  GObject object;
18};
19
20struct _GTestClass
21{
22  GObjectClass parent_class;
23};
24
25static GType my_test_get_type (void);
26static volatile gboolean stopping;
27
28static void my_test_class_init (GTestClass * klass);
29static void my_test_init (GTest * test);
30static void my_test_dispose (GObject * object);
31
32static GObjectClass *parent_class = NULL;
33
34static GType
35my_test_get_type (void)
36{
37  static GType test_type = 0;
38
39  if (!test_type) {
40    static const GTypeInfo test_info = {
41      sizeof (GTestClass),
42      NULL,
43      NULL,
44      (GClassInitFunc) my_test_class_init,
45      NULL,
46      NULL,
47      sizeof (GTest),
48      0,
49      (GInstanceInitFunc) my_test_init,
50      NULL
51    };
52
53    test_type = g_type_register_static (G_TYPE_OBJECT, "GTest",
54        &test_info, 0);
55  }
56  return test_type;
57}
58
59static void
60my_test_class_init (GTestClass * klass)
61{
62  GObjectClass *gobject_class;
63
64  gobject_class = (GObjectClass *) klass;
65
66  parent_class = g_type_class_ref (G_TYPE_OBJECT);
67
68  gobject_class->dispose = my_test_dispose;
69}
70
71static void
72my_test_init (GTest * test)
73{
74  g_print ("init %p\n", test);
75}
76
77static void
78my_test_dispose (GObject * object)
79{
80  GTest *test;
81
82  test = MY_TEST (object);
83
84  g_print ("dispose %p!\n", object);
85
86  G_OBJECT_CLASS (parent_class)->dispose (object);
87}
88
89static void
90my_test_do_refcount (GTest * test)
91{
92  g_object_ref (test);
93  g_object_unref (test);
94}
95
96static gpointer
97run_thread (GTest * test)
98{
99  gint i = 1;
100
101  while (!stopping) {
102    my_test_do_refcount (test);
103    if ((i++ % 10000) == 0) {
104      g_print (".");
105      g_thread_yield(); /* force context switch */
106    }
107  }
108
109  return NULL;
110}
111
112int
113main (int argc, char **argv)
114{
115  gint i;
116  GTest *test1, *test2;
117  GArray *test_threads;
118  const guint n_threads = 5;
119
120  g_thread_init (NULL);
121  g_print ("START: %s\n", argv[0]);
122  g_log_set_always_fatal (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | g_log_set_always_fatal (G_LOG_FATAL_MASK));
123  g_type_init ();
124
125  test1 = g_object_new (G_TYPE_TEST, NULL);
126  test2 = g_object_new (G_TYPE_TEST, NULL);
127
128  test_threads = g_array_new (FALSE, FALSE, sizeof (GThread *));
129
130  stopping = FALSE;
131
132  for (i = 0; i < n_threads; i++) {
133    GThread *thread;
134
135    thread = g_thread_create ((GThreadFunc) run_thread, test1, TRUE, NULL);
136    g_array_append_val (test_threads, thread);
137
138    thread = g_thread_create ((GThreadFunc) run_thread, test2, TRUE, NULL);
139    g_array_append_val (test_threads, thread);
140  }
141  g_usleep (5000000);
142
143  stopping = TRUE;
144
145  g_print ("\nstopping\n");
146
147  /* join all threads */
148  for (i = 0; i < 2 * n_threads; i++) {
149    GThread *thread;
150
151    thread = g_array_index (test_threads, GThread *, i);
152    g_thread_join (thread);
153  }
154
155  g_print ("stopped\n");
156
157  return 0;
158}
159