<commit_before>/*
 * (C) Copyright 2013 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gst/gst.h>

#include "KmsHttpLoop.h"

#define NAME "httploop"

GST_DEBUG_CATEGORY_STATIC (kms_http_loop_debug_category);
#define GST_CAT_DEFAULT kms_http_loop_debug_category

G_DEFINE_TYPE_WITH_CODE (KmsHttpLoop, kms_http_loop,
                         G_TYPE_OBJECT,
                         GST_DEBUG_CATEGORY_INIT (kms_http_loop_debug_category,
                             NAME, 0, "debug category for kurento loop") )

#define KMS_HTTP_LOOP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), KMS_TYPE_HTTP_LOOP, KmsHttpLoopPrivate))

struct _KmsHttpLoopPrivate {
  GThread *thread;
  GRecMutex rmutex;
  GMainLoop *loop;
  GMainContext *context;
  GCond cond;
  GMutex mutex;
  gboolean initialized;
};

#define KMS_HTTP_LOOP_LOCK(elem) \
  (g_rec_mutex_lock (&KMS_HTTP_LOOP ((elem))->priv->rmutex))
#define KMS_HTTP_LOOP_UNLOCK(elem) \
  (g_rec_mutex_unlock (&KMS_HTTP_LOOP ((elem))->priv->rmutex))

/* Object properties */
enum {
  PROP_0,
  PROP_CONTEXT,
  N_PROPERTIES
};

static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };

static gboolean
quit_main_loop (GMainLoop *loop)
{
  GST_DEBUG ("Exiting main loop");

  g_main_loop_quit (loop);

  return G_SOURCE_REMOVE;
}

static gpointer
loop_thread_init (gpointer data)
{
  KmsHttpLoop *self = KMS_HTTP_LOOP (data);
  GMainLoop *loop;
  GMainContext *context;

  KMS_HTTP_LOOP_LOCK (self);
  self->priv->context = g_main_context_new ();
  context = self->priv->context;
  self->priv->loop = g_main_loop_new (context, FALSE);
  loop = self->priv->loop;
  KMS_HTTP_LOOP_UNLOCK (self);

  /* unlock main process because context is already initialized */
  g_mutex_lock (&self->priv->mutex);
  self->priv->initialized = TRUE;
  g_cond_signal (&self->priv->cond);
  g_mutex_unlock (&self->priv->mutex);

  if (!g_main_context_acquire (context) ) {
    GST_ERROR ("Can not acquire context");
    goto end;
  }

  GST_DEBUG ("Running main loop");
  g_main_loop_run (loop);
  g_main_context_release (context);

end:
  GST_DEBUG ("Thread finished");
  g_main_context_unref (context);
  g_main_loop_unref (loop);

  return NULL;
}

static void
kms_http_loop_get_property (GObject *object, guint property_id, GValue *value,
                            GParamSpec *pspec)
{
  KmsHttpLoop *self = KMS_HTTP_LOOP (object);

  KMS_HTTP_LOOP_LOCK (self);

  switch (property_id) {
  case PROP_CONTEXT:
    g_value_set_boxed (value, self->priv->context);
    break;

  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    break;
  }

  KMS_HTTP_LOOP_UNLOCK (self);
}

static void
kms_http_loop_dispose (GObject *obj)
{
  KmsHttpLoop *self = KMS_HTTP_LOOP (obj);

  GST_DEBUG_OBJECT (obj, "Dispose");

  KMS_HTTP_LOOP_LOCK (self);

  if (self->priv->thread != NULL) {
    if (g_thread_self () != self->priv->thread) {
      GThread *aux = self->priv->thread;

      kms_http_loop_idle_add (self, (GSourceFunc) quit_main_loop,
                              self->priv->loop);
      self->priv->thread = NULL;
      KMS_HTTP_LOOP_UNLOCK (self);
      g_thread_join (aux);
      KMS_HTTP_LOOP_LOCK (self);
    } else {
      /* self thread does not need to wait for itself */
      quit_main_loop (self->priv->loop);
      g_thread_unref (self->priv->thread);
      self->priv->thread = NULL;
    }
  }

  KMS_HTTP_LOOP_UNLOCK (self);

  G_OBJECT_CLASS (kms_http_loop_parent_class)->dispose (obj);
}

static void
kms_http_loop_finalize (GObject *obj)
{
  KmsHttpLoop *self = KMS_HTTP_LOOP (obj);

  GST_DEBUG_OBJECT (obj, "Finalize");

  g_rec_mutex_clear (&self->priv->rmutex);
  g_mutex_clear (&self->priv->mutex);
  g_cond_clear (&self->priv->cond);

  G_OBJECT_CLASS (kms_http_loop_parent_class)->finalize (obj);
}

static void
kms_http_loop_class_init (KmsHttpLoopClass *klass)
{
  GObjectClass *objclass = G_OBJECT_CLASS (klass);

  objclass->dispose = kms_http_loop_dispose;
  objclass->finalize = kms_http_loop_finalize;
  objclass->get_property = kms_http_loop_get_property;

  /* Install properties */
  obj_properties[PROP_CONTEXT] = g_param_spec_boxed ("context",
                                 "Main loop context",
                                 "Main loop context",
                                 G_TYPE_MAIN_CONTEXT,
                                 (GParamFlags) (G_PARAM_READABLE) );

  g_object_class_install_properties (objclass, N_PROPERTIES, obj_properties);

  /* Registers a private structure for the instantiatable type */
  g_type_class_add_private (klass, sizeof (KmsHttpLoopPrivate) );
}

static void
kms_http_loop_init (KmsHttpLoop *self)
{
  self->priv = KMS_HTTP_LOOP_GET_PRIVATE (self);
  g_rec_mutex_init (&self->priv->rmutex);
  g_cond_init (&self->priv->cond);<commit_msg>KmsHttpLoop: Fix bad read while disposing kmsloop<commit_after>/*
 * (C) Copyright 2013 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gst/gst.h>

#include "KmsHttpLoop.h"

#define NAME "httploop"

GST_DEBUG_CATEGORY_STATIC (kms_http_loop_debug_category);
#define GST_CAT_DEFAULT kms_http_loop_debug_category

G_DEFINE_TYPE_WITH_CODE (KmsHttpLoop, kms_http_loop,
                         G_TYPE_OBJECT,
                         GST_DEBUG_CATEGORY_INIT (kms_http_loop_debug_category,
                             NAME, 0, "debug category for kurento loop") )

#define KMS_HTTP_LOOP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), KMS_TYPE_HTTP_LOOP, KmsHttpLoopPrivate))

struct _KmsHttpLoopPrivate {
  GThread *thread;
  GRecMutex rmutex;
  GMainLoop *loop;
  GMainContext *context;
  GCond cond;
  GMutex mutex;
  gboolean initialized;
};

#define KMS_HTTP_LOOP_LOCK(elem) \
  (g_rec_mutex_lock (&KMS_HTTP_LOOP ((elem))->priv->rmutex))
#define KMS_HTTP_LOOP_UNLOCK(elem) \
  (g_rec_mutex_unlock (&KMS_HTTP_LOOP ((elem))->priv->rmutex))

/* Object properties */
enum {
  PROP_0,
  PROP_CONTEXT,
  N_PROPERTIES
};

static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };

static gboolean
quit_main_loop (KmsHttpLoop *self)
{
  GST_DEBUG ("Exiting main loop");

  g_main_loop_quit (self->priv->loop);
  g_main_context_release (self->priv->context);

  return G_SOURCE_REMOVE;
}

static gpointer
loop_thread_init (gpointer data)
{
  KmsHttpLoop *self = KMS_HTTP_LOOP (data);
  GMainLoop *loop;
  GMainContext *context;

  KMS_HTTP_LOOP_LOCK (self);
  self->priv->context = g_main_context_new ();
  context = self->priv->context;
  self->priv->loop = g_main_loop_new (context, FALSE);
  loop = self->priv->loop;
  KMS_HTTP_LOOP_UNLOCK (self);

  /* unlock main process because context is already initialized */
  g_mutex_lock (&self->priv->mutex);
  self->priv->initialized = TRUE;
  g_cond_signal (&self->priv->cond);
  g_mutex_unlock (&self->priv->mutex);

  if (!g_main_context_acquire (context) ) {
    GST_ERROR ("Can not acquire context");
    goto end;
  }

  GST_DEBUG ("Running main loop");
  g_main_loop_run (loop);

end:
  GST_DEBUG ("Thread finished");

  return NULL;
}

static void
kms_http_loop_get_property (GObject *object, guint property_id, GValue *value,
                            GParamSpec *pspec)
{
  KmsHttpLoop *self = KMS_HTTP_LOOP (object);

  KMS_HTTP_LOOP_LOCK (self);

  switch (property_id) {
  case PROP_CONTEXT:
    g_value_set_boxed (value, self->priv->context);
    break;

  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    break;
  }

  KMS_HTTP_LOOP_UNLOCK (self);
}

static void
kms_http_loop_dispose (GObject *obj)
{
  KmsHttpLoop *self = KMS_HTTP_LOOP (obj);

  GST_DEBUG_OBJECT (obj, "Dispose");

  KMS_HTTP_LOOP_LOCK (self);

  if (self->priv->thread != NULL) {
    if (g_thread_self () != self->priv->thread) {
      GThread *aux = self->priv->thread;

      kms_http_loop_idle_add (self, (GSourceFunc) quit_main_loop,
                              self);
      self->priv->thread = NULL;
      KMS_HTTP_LOOP_UNLOCK (self);
      g_thread_join (aux);
      KMS_HTTP_LOOP_LOCK (self);
    } else {
      /* self thread does not need to wait for itself */
      quit_main_loop (self);
      g_thread_unref (self->priv->thread);
      self->priv->thread = NULL;
    }
  }

  KMS_HTTP_LOOP_UNLOCK (self);

  G_OBJECT_CLASS (kms_http_loop_parent_class)->dispose (obj);
}

static void
kms_http_loop_finalize (GObject *obj)
{
  KmsHttpLoop *self = KMS_HTTP_LOOP (obj);

  GST_DEBUG_OBJECT (obj, "Finalize");

  if (self->priv->context != NULL) {
    g_main_context_unref (self->priv->context);
  }

  if (self->priv->loop != NULL) {
    g_main_loop_unref (self->priv->loop);
  }

  g_rec_mutex_clear (&self->priv->rmutex);
  g_mutex_clear (&self->priv->mutex);
  g_cond_clear (&self->priv->cond);

  G_OBJECT_CLASS (kms_http_loop_parent_class)->finalize (obj);
}

static void
kms_http_loop_class_init (KmsHttpLoopClass *klass)
{
  GObjectClass *objclass = G_OBJECT_CLASS (klass);

  objclass->dispose = kms_http_loop_dispose;
  objclass->finalize = kms_http_loop_finalize;
  objclass->get_property = kms_http_loop_get_property;

  /* Install properties */
  obj_properties[PROP_CONTEXT] = g_param_spec_boxed ("context",
                                 "Main loop context",
                                 "Main loop context",
                                 G_TYPE_MAIN_CONTEXT,
                                 (GParamFlags) (G_PARAM_READABLE) );

  g_object_class_install_properties (objclass, N_PROPERTIES, obj_properties);

  /* Registers a private structure for the instantiatable type */
  g_type_class_add_private (klass, sizeof (KmsHttpLoopPrivate) );
}

static void
kms_http_loop_init (KmsHttpLoop *self)
{
  self->priv = KMS_HTTP_LOOP_GET_PRIVATE (self);
  self->priv->context = NULL;
  self->priv->loop = NULL;
  g_rec_mutex_init (&self->priv->rmutex);
  g_cond_init (&self->priv->cond);
{'fraction_non_alphanumeric': 0.10918591859185918, 'fraction_numerical': 0.0018335166850018336, 'mean_word_length': 3.7082434182132067, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 125, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5081614', 'n_tokens_mistral': 3891, 'n_tokens_neox': 3824, 'n_words': 819}