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
12static GRand *rand;
13
14typedef struct _GTest GTest;
15typedef struct _GTestClass GTestClass;
16
17struct _GTest
18{
19  GObject object;
20
21  gint value;
22};
23
24struct _GTestClass
25{
26  GObjectClass parent_class;
27
28  void (*test_signal1) (GTest * test, gint an_int);
29  void (*test_signal2) (GTest * test, gint an_int);
30};
31
32static GType my_test_get_type (void);
33static volatile gboolean stopping;
34
35/* Element signals and args */
36enum
37{
38  TEST_SIGNAL1,
39  TEST_SIGNAL2,
40  /* add more above */
41  LAST_SIGNAL
42};
43
44enum
45{
46  ARG_0,
47  ARG_TEST_PROP
48};
49
50static void my_test_class_init (GTestClass * klass);
51static void my_test_init (GTest * test);
52static void my_test_dispose (GObject * object);
53
54static void signal2_handler (GTest * test, gint anint);
55
56static void my_test_set_property (GObject * object, guint prop_id,
57    const GValue * value, GParamSpec * pspec);
58static void my_test_get_property (GObject * object, guint prop_id,
59    GValue * value, GParamSpec * pspec);
60
61static GObjectClass *parent_class = NULL;
62
63static guint my_test_signals[LAST_SIGNAL] = { 0 };
64
65static GType
66my_test_get_type (void)
67{
68  static GType test_type = 0;
69
70  if (!test_type) {
71    static const GTypeInfo test_info = {
72      sizeof (GTestClass),
73      NULL,
74      NULL,
75      (GClassInitFunc) my_test_class_init,
76      NULL,
77      NULL,
78      sizeof (GTest),
79      0,
80      (GInstanceInitFunc) my_test_init,
81      NULL
82    };
83
84    rand = g_rand_new();
85
86    test_type = g_type_register_static (G_TYPE_OBJECT, "GTest",
87        &test_info, 0);
88  }
89  return test_type;
90}
91
92static void
93my_test_class_init (GTestClass * klass)
94{
95  GObjectClass *gobject_class;
96
97  gobject_class = (GObjectClass *) klass;
98
99  parent_class = g_type_class_ref (G_TYPE_OBJECT);
100
101  if (!g_thread_supported ())
102    g_thread_init (NULL);
103
104  gobject_class->dispose = my_test_dispose;
105  gobject_class->set_property = my_test_set_property;
106  gobject_class->get_property = my_test_get_property;
107
108  my_test_signals[TEST_SIGNAL1] =
109      g_signal_new ("test-signal1", G_TYPE_FROM_CLASS (klass),
110      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GTestClass, test_signal1), NULL,
111      NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
112  my_test_signals[TEST_SIGNAL2] =
113      g_signal_new ("test-signal2", G_TYPE_FROM_CLASS (klass),
114      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GTestClass, test_signal2), NULL,
115      NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
116
117  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TEST_PROP,
118      g_param_spec_int ("test-prop", "Test Prop", "Test property",
119          0, 1, 0, G_PARAM_READWRITE));
120
121  klass->test_signal2 = signal2_handler;
122}
123
124static void
125my_test_init (GTest * test)
126{
127  g_print ("init %p\n", test);
128
129  test->value = 0;
130}
131
132static void
133my_test_dispose (GObject * object)
134{
135  GTest *test;
136
137  test = MY_TEST (object);
138
139  g_print ("dispose %p!\n", object);
140
141  G_OBJECT_CLASS (parent_class)->dispose (object);
142}
143
144static void
145my_test_set_property (GObject * object, guint prop_id,
146                      const GValue * value, GParamSpec * pspec)
147{
148  GTest *test;
149
150  test = MY_TEST (object);
151
152  switch (prop_id) {
153    case ARG_TEST_PROP:
154      test->value = g_value_get_int (value);
155      break;
156    default:
157      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
158      break;
159  }
160}
161
162static void
163my_test_get_property (GObject * object, guint prop_id,
164                      GValue * value, GParamSpec * pspec)
165{
166  GTest *test;
167
168  test = MY_TEST (object);
169
170  switch (prop_id) {
171    case ARG_TEST_PROP:
172      g_value_set_int (value, test->value);
173      break;
174    default:
175      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
176      break;
177  }
178}
179
180static void
181my_test_do_signal1 (GTest * test)
182{
183  g_signal_emit (G_OBJECT (test), my_test_signals[TEST_SIGNAL1], 0, 0);
184}
185
186static void
187signal2_handler (GTest * test, gint anint)
188{
189}
190
191static void
192my_test_do_signal2 (GTest * test)
193{
194  g_signal_emit (G_OBJECT (test), my_test_signals[TEST_SIGNAL2], 0, 0);
195}
196
197static void
198my_test_do_prop (GTest * test)
199{
200  test->value = g_rand_int (rand);
201  g_object_notify (G_OBJECT (test), "test-prop");
202}
203
204static gpointer
205run_thread (GTest * test)
206{
207  gint i = 1;
208
209  while (!stopping) {
210    if (TESTNUM == 1)
211      my_test_do_signal1 (test);
212    if (TESTNUM == 2)
213      my_test_do_signal2 (test);
214    if (TESTNUM == 3)
215      my_test_do_prop (test);
216    if ((i++ % 10000) == 0) {
217      g_print (".");
218      g_thread_yield(); /* force context switch */
219    }
220  }
221
222  return NULL;
223}
224
225static void
226notify (GObject *object, GParamSpec *spec, gpointer user_data)
227{
228  gint value;
229
230  g_object_get (object, "test-prop", &value, NULL);
231  /*g_print ("+ %d", value);*/
232}
233
234int
235main (int argc, char **argv)
236{
237  gint i;
238  GTest *test1, *test2;
239  GArray *test_threads;
240  const gint n_threads = 1;
241
242  g_thread_init (NULL);
243  g_print ("START: %s\n", argv[0]);
244  g_log_set_always_fatal (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | g_log_set_always_fatal (G_LOG_FATAL_MASK));
245  g_type_init ();
246
247  test1 = g_object_new (G_TYPE_TEST, NULL);
248  test2 = g_object_new (G_TYPE_TEST, NULL);
249
250  g_signal_connect (test1, "notify::test-prop", G_CALLBACK (notify), NULL);
251  g_signal_connect (test1, "test-signal1", G_CALLBACK (notify), NULL);
252  g_signal_connect (test1, "test-signal2", G_CALLBACK (notify), NULL);
253
254  test_threads = g_array_new (FALSE, FALSE, sizeof (GThread *));
255
256  stopping = FALSE;
257
258  for (i = 0; i < n_threads; i++) {
259    GThread *thread;
260
261    thread = g_thread_create ((GThreadFunc) run_thread, test1, TRUE, NULL);
262    g_array_append_val (test_threads, thread);
263
264    thread = g_thread_create ((GThreadFunc) run_thread, test2, TRUE, NULL);
265    g_array_append_val (test_threads, thread);
266  }
267  g_usleep (5000000);
268
269  stopping = TRUE;
270
271  g_print ("\nstopping\n");
272
273  /* join all threads */
274  for (i = 0; i < 2 * n_threads; i++) {
275    GThread *thread;
276
277    thread = g_array_index (test_threads, GThread *, i);
278    g_thread_join (thread);
279  }
280
281  g_print ("stopped\n");
282
283  return 0;
284}
285