/*-
 * $Id: rr.c,v 1.22 2002/08/19 18:05:43 jonas Exp $
 *
 * See the file LICENSE for redistribution information. 
 * If you have not received a copy of the license, please contact CodeFactory
 * by email at info@codefactory.se, or on the web at http://www.codefactory.se/
 * You may also write to: CodeFactory AB, SE-903 47, Umeå, Sweden.
 *
 * Copyright (c) 2002 Jonas Borgström <jonas@codefactory.se>
 * Copyright (c) 2002 Daniel Lundin   <daniel@codefactory.se>
 * Copyright (c) 2002 CodeFactory AB.  All rights reserved.
 */

#include <librr/rr.h>

#include <stdlib.h>

#define RR_DEFAULT_MAX_WORK_THREADS 1

static gint rr_max_work_threads = RR_DEFAULT_MAX_WORK_THREADS;

static RRWorkPool *rr_wp = NULL;
static GMainLoop *rr_main_loop = NULL;
static GMainContext *rr_main_context = NULL;
static GThread *rr_bg_thread = NULL;

GQuark
rr_error_quark (void)
{
	static GQuark quark;
	if (!quark)
		quark = g_quark_from_static_string ("rr_error");
	return quark;
}

GQuark
rr_beep_code_quark (void)
{
	static GQuark quark;
	if (!quark)
		quark = g_quark_from_static_string ("rr_beep_code");
	return quark;
}

static void
gobject_bug_workaround (void)
{
	GType type;
	RRGreeting *greeting;

	type = RR_TYPE_CHANNEL;
	type = RR_TYPE_CONNECTION;
	type = RR_TYPE_TCP_CONNECTION;
	type = RR_TYPE_TCP_LISTENER;
	type = RR_TYPE_FRAME;
	type = RR_TYPE_FRAME_SEQ;
	type = RR_TYPE_MESSAGE;
	type = RR_TYPE_GREETING;
	type = RR_TYPE_MESSAGE_START;
	type = RR_TYPE_MESSAGE_CLOSE;
	type = RR_TYPE_MESSAGE_ERROR;
	type = RR_TYPE_MESSAGE_STATIC;
	type = RR_TYPE_PROFILE_REGISTRY;

	greeting = rr_greeting_new (NULL, NULL, NULL);
	g_object_unref (G_OBJECT (greeting));
}

static gpointer
run_thread (gpointer data)
{
	g_main_loop_run (rr_main_loop);
	return NULL;
}

/**
 * rr_init:
 * @argc: a pointer to argc or %NULL.
 * @argv: a pointer to argv or %NULL.
 * @error: location to return an error.
 * 
 * Initializes RoadRunner and starts the event thread.
 * 
 * Return value: TRUE on success, FALSE on failure.
 **/
gboolean
rr_init (gint *argc, gchar ***argv, GError **error)
{
	const gchar *str;

	if (!g_thread_supported ())
		g_thread_init (NULL);

	rr_debug_init ();

	if ((str = getenv ("RR_MAX_WORK_THREADS"))) {
		gint num = atoi (str);
		if (num > 0)
			rr_max_work_threads = num;
	}

	rr_wp = rr_work_pool_new (rr_max_work_threads);

	gobject_bug_workaround ();

	rr_main_context = g_main_context_new ();
	rr_main_loop = g_main_loop_new (rr_main_context, FALSE);

	if ((rr_bg_thread = g_thread_create (run_thread,
					     NULL, TRUE, error)) == NULL)
		return FALSE;
	else
		return TRUE;
}


/**
 * rr_main_work_pool_push:
 * @gid: a thread group id.
 * @func: a function to execute by one thread in the work pool.
 * @data: first argument to @func
 * @user_data: second argument to @func
 * 
 * Inserts @func to the list of task to be executed by the roadrunner wide
 * work pool. The work pool guarantees that two or more tasks with the same
 * @gid will never be executed in parallel.
 **/
void
rr_main_work_pool_push (RRWPGroup gid, GFunc func, 
			gpointer data, gpointer user_data)
{
	g_return_if_fail (rr_wp != NULL);
	rr_work_pool_push (rr_wp, gid, func, data, user_data);
}

/**
 * rr_main_work_pool_join:
 * @gid: a thread group id
 * 
 * blocks until all tasks in the roadrunner global work pool of the given 
 * @gid are executed.
 **/
void
rr_main_work_pool_join (RRWPGroup gid)
{
	g_return_if_fail (rr_wp != NULL);
	rr_work_pool_join (rr_wp, gid);
}

/**
 * rr_quit:
 * @error: location to return an error.
 * 
 * Terminates the main loop. This will unblock rr_wait_until_done.
 * 
 * Return value: %TRUE on success, %FALSE on failure.
 **/
gboolean
rr_quit (GError **error)
{
	if (rr_main_loop == NULL) {
		g_set_error (error, RR_ERROR, RR_ERROR_OTHER,
			     "The main loop doesn't exist.");
		return FALSE;
	}
		g_main_loop_quit (rr_main_loop);

	return TRUE;
}

/**
 * rr_wait_until_done:
 * @error: location to return an error.
 * 
 * Blocks until the RoadRunner event loop is done.
 * (when rr_quit is called).
 * 
 * Return value: TRUE on success, FALSE on failure.
 **/
gboolean
rr_wait_until_done (GError **error)
{
	if (rr_bg_thread) {
		g_thread_join (rr_bg_thread);
		rr_bg_thread = NULL;
	}

	rr_work_pool_free (rr_wp);
	rr_wp = NULL;

	g_main_loop_unref (rr_main_loop);
	g_main_context_unref (rr_main_context);
	rr_main_loop = NULL;
	rr_main_context = NULL;

	rr_debug_exit ();

	return TRUE;
}

/**
 * rr_exit:
 * @error: location to return an error.
 * 
 * Terminates the RoadRunner event thread and free the resources
 * allocated by #rr_init.
 * 
 * Return value: TRUE on success, FALSE on failure.
 **/
gboolean
rr_exit (GError **error)
{
	if (!rr_quit (error))
		return FALSE;
	if (!rr_wait_until_done (error))
		return FALSE;

	return TRUE;
}

GMainContext *
rr_get_main_context ()
{
	return rr_main_context;
}

/**
 * rr_set_max_work_threads:
 * @max: maximum number of threads.
 * 
 * Sets the maximum number of threads roadrunner will use. This function
 * should be called before rr_init.
 **/
void
rr_set_max_work_threads (int max)
{
	rr_max_work_threads = max;
}

/**
 * rr_get_max_work_threads:
 *
 * Returns the maximum number of threads that roadrunner will use.
 * 
 * Return value: the number of threads.
 **/
gint
rr_get_max_work_threads (void)
{
	return rr_max_work_threads;
}


syntax highlighted by Code2HTML, v. 0.9.1