Blame glib/tests/642026.c

Packit ae235b
/*
Packit ae235b
 * Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
Packit ae235b
 * Copyright © 2011 Nokia Corporation
Packit ae235b
 *
Packit ae235b
 * This program is free software; you can redistribute it and/or
Packit ae235b
 * modify it under the terms of the GNU Lesser General Public
Packit ae235b
 * License as published by the Free Software Foundation; either
Packit ae235b
 * version 2.1 of the License, or (at your option) any later version.
Packit ae235b
 *
Packit ae235b
 * See the included COPYING file for more information.
Packit ae235b
 */
Packit ae235b
Packit ae235b
#define GLIB_DISABLE_DEPRECATION_WARNINGS
Packit ae235b
Packit ae235b
#include <glib.h>
Packit ae235b
Packit ae235b
/* On smcv's laptop, 1e4 iterations didn't always exhibit the bug, but 1e5
Packit ae235b
 * iterations exhibited it 10/10 times in practice. YMMV. */
Packit ae235b
#define ITERATIONS 100000
Packit ae235b
Packit ae235b
static GStaticPrivate sp;
Packit ae235b
static GMutex *mutex;
Packit ae235b
static GCond *cond;
Packit ae235b
static guint i;
Packit ae235b
Packit ae235b
static volatile gint freed = 0;
Packit ae235b
Packit ae235b
static void
Packit ae235b
notify (gpointer p)
Packit ae235b
{
Packit ae235b
  if (!g_atomic_int_compare_and_exchange (&freed, 0, 1))
Packit ae235b
    {
Packit ae235b
      g_error ("someone already freed it after %u iterations", i);
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static gpointer thread_func (gpointer nil)
Packit ae235b
{
Packit ae235b
  /* wait for main thread to reach its g_cond_wait call */
Packit ae235b
  g_mutex_lock (mutex);
Packit ae235b
Packit ae235b
  g_static_private_set (&sp, &sp, notify);
Packit ae235b
  g_cond_broadcast (cond);
Packit ae235b
  g_mutex_unlock (mutex);
Packit ae235b
Packit ae235b
  return nil;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
testcase (void)
Packit ae235b
{
Packit ae235b
  g_test_bug ("642026");
Packit ae235b
Packit ae235b
  mutex = g_mutex_new ();
Packit ae235b
  cond = g_cond_new ();
Packit ae235b
Packit ae235b
  g_mutex_lock (mutex);
Packit ae235b
Packit ae235b
  for (i = 0; i < ITERATIONS; i++)
Packit ae235b
    {
Packit ae235b
      GThread *t1;
Packit ae235b
Packit ae235b
      g_static_private_init (&sp);
Packit ae235b
      freed = 0;
Packit ae235b
Packit ae235b
      t1 = g_thread_create (thread_func, NULL, TRUE, NULL);
Packit ae235b
      g_assert (t1 != NULL);
Packit ae235b
Packit ae235b
      /* wait for t1 to set up its thread-private data */
Packit ae235b
      g_cond_wait (cond, mutex);
Packit ae235b
Packit ae235b
      /* exercise the bug, by racing with t1 to free the private data */
Packit ae235b
      g_static_private_free (&sp);
Packit ae235b
      g_thread_join (t1);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_cond_free (cond);
Packit ae235b
  g_mutex_unlock (mutex);
Packit ae235b
  g_mutex_free (mutex);
Packit ae235b
}
Packit ae235b
Packit ae235b
int
Packit ae235b
main (int argc,
Packit ae235b
    char **argv)
Packit ae235b
{
Packit ae235b
  g_test_init (&argc, &argv, NULL);
Packit ae235b
  g_test_bug_base ("https://bugzilla.gnome.org/show_bug.cgi?id=");
Packit ae235b
Packit ae235b
  g_test_add_func ("/glib/642026", testcase);
Packit ae235b
Packit ae235b
  return g_test_run ();
Packit ae235b
}