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