1 | #include <glib.h> |
2 | #include <glib-object.h> |
3 | |
4 | #ifdef G_OS_UNIX |
5 | #include <unistd.h> |
6 | #endif |
7 | |
8 | #define G_TYPE_TEST (my_test_get_type ()) |
9 | #define MY_TEST(test) (G_TYPE_CHECK_INSTANCE_CAST ((test), G_TYPE_TEST, GTest)) |
10 | #define MY_IS_TEST(test) (G_TYPE_CHECK_INSTANCE_TYPE ((test), G_TYPE_TEST)) |
11 | #define MY_TEST_CLASS(tclass) (G_TYPE_CHECK_CLASS_CAST ((tclass), G_TYPE_TEST, GTestClass)) |
12 | #define MY_IS_TEST_CLASS(tclass) (G_TYPE_CHECK_CLASS_TYPE ((tclass), G_TYPE_TEST)) |
13 | #define MY_TEST_GET_CLASS(test) (G_TYPE_INSTANCE_GET_CLASS ((test), G_TYPE_TEST, GTestClass)) |
14 | |
15 | enum { |
16 | PROP_0, |
17 | PROP_DUMMY |
18 | }; |
19 | |
20 | typedef struct _GTest GTest; |
21 | typedef struct _GTestClass GTestClass; |
22 | |
23 | struct _GTest |
24 | { |
25 | GObject object; |
26 | gint id; |
27 | gint dummy; |
28 | |
29 | gint count; |
30 | }; |
31 | |
32 | struct _GTestClass |
33 | { |
34 | GObjectClass parent_class; |
35 | }; |
36 | |
37 | static GType my_test_get_type (void); |
38 | static gboolean stopping; |
39 | |
40 | static void my_test_class_init (GTestClass * klass); |
41 | static void my_test_init (GTest * test); |
42 | static void my_test_dispose (GObject * object); |
43 | static void my_test_get_property (GObject *object, |
44 | guint prop_id, |
45 | GValue *value, |
46 | GParamSpec *pspec); |
47 | static void my_test_set_property (GObject *object, |
48 | guint prop_id, |
49 | const GValue *value, |
50 | GParamSpec *pspec); |
51 | |
52 | static GObjectClass *parent_class = NULL; |
53 | |
54 | static GType |
55 | my_test_get_type (void) |
56 | { |
57 | static GType test_type = 0; |
58 | |
59 | if (!test_type) { |
60 | const GTypeInfo test_info = { |
61 | sizeof (GTestClass), |
62 | NULL, |
63 | NULL, |
64 | (GClassInitFunc) my_test_class_init, |
65 | NULL, |
66 | NULL, |
67 | sizeof (GTest), |
68 | 0, |
69 | (GInstanceInitFunc) my_test_init, |
70 | NULL |
71 | }; |
72 | |
73 | test_type = g_type_register_static (G_TYPE_OBJECT, type_name: "GTest" , info: &test_info, flags: 0); |
74 | } |
75 | return test_type; |
76 | } |
77 | |
78 | static void |
79 | my_test_class_init (GTestClass * klass) |
80 | { |
81 | GObjectClass *gobject_class; |
82 | |
83 | gobject_class = (GObjectClass *) klass; |
84 | |
85 | parent_class = g_type_class_ref (G_TYPE_OBJECT); |
86 | |
87 | gobject_class->dispose = my_test_dispose; |
88 | gobject_class->get_property = my_test_get_property; |
89 | gobject_class->set_property = my_test_set_property; |
90 | |
91 | g_object_class_install_property (oclass: gobject_class, |
92 | property_id: PROP_DUMMY, |
93 | pspec: g_param_spec_int (name: "dummy" , |
94 | NULL, |
95 | NULL, |
96 | minimum: 0, G_MAXINT, default_value: 0, |
97 | flags: G_PARAM_READWRITE)); |
98 | } |
99 | |
100 | static void |
101 | my_test_init (GTest * test) |
102 | { |
103 | static guint static_id = 1; |
104 | test->id = static_id++; |
105 | } |
106 | |
107 | static void |
108 | my_test_dispose (GObject * object) |
109 | { |
110 | G_OBJECT_CLASS (parent_class)->dispose (object); |
111 | } |
112 | |
113 | static void |
114 | my_test_get_property (GObject *object, |
115 | guint prop_id, |
116 | GValue *value, |
117 | GParamSpec *pspec) |
118 | { |
119 | GTest *test; |
120 | |
121 | test = MY_TEST (object); |
122 | |
123 | switch (prop_id) |
124 | { |
125 | case PROP_DUMMY: |
126 | g_value_set_int (value, v_int: test->dummy); |
127 | break; |
128 | default: |
129 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
130 | break; |
131 | } |
132 | } |
133 | |
134 | static void |
135 | my_test_set_property (GObject *object, |
136 | guint prop_id, |
137 | const GValue *value, |
138 | GParamSpec *pspec) |
139 | { |
140 | GTest *test; |
141 | |
142 | test = MY_TEST (object); |
143 | |
144 | switch (prop_id) |
145 | { |
146 | case PROP_DUMMY: |
147 | test->dummy = g_value_get_int (value); |
148 | break; |
149 | default: |
150 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
151 | break; |
152 | } |
153 | } |
154 | |
155 | static void |
156 | dummy_notify (GObject *object, |
157 | GParamSpec *pspec) |
158 | { |
159 | GTest *test; |
160 | |
161 | test = MY_TEST (object); |
162 | |
163 | test->count++; |
164 | } |
165 | |
166 | static void |
167 | my_test_do_property (GTest * test) |
168 | { |
169 | gint dummy; |
170 | |
171 | g_object_get (object: test, first_property_name: "dummy" , &dummy, NULL); |
172 | g_object_set (object: test, first_property_name: "dummy" , dummy + 1, NULL); |
173 | } |
174 | |
175 | static gpointer |
176 | run_thread (GTest * test) |
177 | { |
178 | gint i = 1; |
179 | |
180 | while (!g_atomic_int_get (&stopping)) { |
181 | my_test_do_property (test); |
182 | if ((i++ % 10000) == 0) |
183 | { |
184 | g_print (format: ".%c" , 'a' + test->id); |
185 | g_thread_yield(); /* force context switch */ |
186 | } |
187 | } |
188 | |
189 | return NULL; |
190 | } |
191 | |
192 | int |
193 | main (int argc, char **argv) |
194 | { |
195 | #define N_THREADS 5 |
196 | GThread *test_threads[N_THREADS]; |
197 | GTest *test_objects[N_THREADS]; |
198 | gint i; |
199 | |
200 | g_print (format: "START: %s\n" , argv[0]); |
201 | g_log_set_always_fatal (fatal_mask: G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | g_log_set_always_fatal (G_LOG_FATAL_MASK)); |
202 | |
203 | for (i = 0; i < N_THREADS; i++) { |
204 | GTest *test; |
205 | |
206 | test = g_object_new (G_TYPE_TEST, NULL); |
207 | test_objects[i] = test; |
208 | |
209 | g_assert (test->count == test->dummy); |
210 | g_signal_connect (test, "notify::dummy" , G_CALLBACK (dummy_notify), NULL); |
211 | } |
212 | |
213 | g_atomic_int_set (&stopping, FALSE); |
214 | |
215 | for (i = 0; i < N_THREADS; i++) |
216 | test_threads[i] = g_thread_create (func: (GThreadFunc) run_thread, data: test_objects[i], TRUE, NULL); |
217 | |
218 | g_usleep (microseconds: 3000000); |
219 | |
220 | g_atomic_int_set (&stopping, TRUE); |
221 | g_print (format: "\nstopping\n" ); |
222 | |
223 | /* join all threads */ |
224 | for (i = 0; i < N_THREADS; i++) |
225 | g_thread_join (thread: test_threads[i]); |
226 | |
227 | g_print (format: "stopped\n" ); |
228 | |
229 | for (i = 0; i < N_THREADS; i++) { |
230 | GTest *test = test_objects[i]; |
231 | |
232 | g_assert (test->count == test->dummy); |
233 | g_object_unref (object: test); |
234 | } |
235 | |
236 | return 0; |
237 | } |
238 | |