mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	Remove DBus and work towards something like wayland. Remove more glib stuff from the client code
		
			
				
	
	
		
			285 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			285 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* Pinos
 | 
						|
 * Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
 | 
						|
 *
 | 
						|
 * This library is free software; you can redistribute it and/or
 | 
						|
 * modify it under the terms of the GNU Library General Public
 | 
						|
 * License as published by the Free Software Foundation; either
 | 
						|
 * version 2 of the License, or (at your option) any later version.
 | 
						|
 *
 | 
						|
 * 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
 | 
						|
 * Library General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU Library General Public
 | 
						|
 * License along with this library; if not, write to the
 | 
						|
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 | 
						|
 * Boston, MA 02110-1301, USA.
 | 
						|
 */
 | 
						|
 | 
						|
#include <pthread.h>
 | 
						|
 | 
						|
#include "pinos.h"
 | 
						|
#include "thread-mainloop.h"
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  PinosThreadMainLoop this;
 | 
						|
 | 
						|
  char *name;
 | 
						|
 | 
						|
  pthread_mutex_t lock;
 | 
						|
  pthread_cond_t  cond;
 | 
						|
  pthread_cond_t  accept_cond;
 | 
						|
 | 
						|
  bool running;
 | 
						|
  pthread_t       thread;
 | 
						|
 | 
						|
  SpaSource *event;
 | 
						|
 | 
						|
  int n_waiting;
 | 
						|
  int n_waiting_for_accept;
 | 
						|
} PinosThreadMainLoopImpl;
 | 
						|
 | 
						|
static void
 | 
						|
pre_hook (SpaLoopControl *ctrl,
 | 
						|
          void           *data)
 | 
						|
{
 | 
						|
  PinosThreadMainLoopImpl *impl = data;
 | 
						|
  pthread_mutex_unlock (&impl->lock);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
post_hook (SpaLoopControl *ctrl,
 | 
						|
           void           *data)
 | 
						|
{
 | 
						|
  PinosThreadMainLoopImpl *impl = data;
 | 
						|
  pthread_mutex_lock (&impl->lock);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
do_stop (SpaSource *source,
 | 
						|
         void      *data)
 | 
						|
{
 | 
						|
  PinosThreadMainLoopImpl *impl = data;
 | 
						|
  impl->running = false;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * pinos_thread_main_loop_new:
 | 
						|
 * @context: a #GMainContext
 | 
						|
 * @name: a thread name
 | 
						|
 *
 | 
						|
 * Make a new #PinosThreadMainLoop that will run a mainloop on @context in
 | 
						|
 * a thread with @name.
 | 
						|
 *
 | 
						|
 * Returns: a #PinosThreadMainLoop
 | 
						|
 */
 | 
						|
PinosThreadMainLoop *
 | 
						|
pinos_thread_main_loop_new (PinosLoop  *loop,
 | 
						|
                            const char *name)
 | 
						|
{
 | 
						|
  PinosThreadMainLoopImpl *impl;
 | 
						|
  PinosThreadMainLoop *this;
 | 
						|
 | 
						|
  impl = calloc (1, sizeof (PinosThreadMainLoopImpl));
 | 
						|
  this = &impl->this;
 | 
						|
  pinos_log_debug ("thread-mainloop %p: new", impl);
 | 
						|
 | 
						|
  this->loop = loop;
 | 
						|
  if (name)
 | 
						|
    this->name = strdup (name);
 | 
						|
 | 
						|
  pinos_loop_set_hooks (loop,
 | 
						|
                        pre_hook,
 | 
						|
                        post_hook,
 | 
						|
                        impl);
 | 
						|
 | 
						|
  pinos_signal_init (&this->destroy_signal);
 | 
						|
 | 
						|
  pthread_mutex_init (&impl->lock, NULL);
 | 
						|
  pthread_cond_init (&impl->cond, NULL);
 | 
						|
  pthread_cond_init (&impl->accept_cond, NULL);
 | 
						|
 | 
						|
  impl->event = pinos_loop_add_event (this->loop,
 | 
						|
                                      do_stop,
 | 
						|
                                      impl);
 | 
						|
 | 
						|
  return this;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
pinos_thread_main_loop_destroy (PinosThreadMainLoop *loop)
 | 
						|
{
 | 
						|
  PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this);
 | 
						|
 | 
						|
  pinos_signal_emit (&loop->destroy_signal, loop);
 | 
						|
 | 
						|
  if (loop->name)
 | 
						|
    free (loop->name);
 | 
						|
  pthread_mutex_destroy (&impl->lock);
 | 
						|
  pthread_cond_destroy (&impl->cond);
 | 
						|
  pthread_cond_destroy (&impl->accept_cond);
 | 
						|
 | 
						|
  free (impl);
 | 
						|
}
 | 
						|
 | 
						|
static void *
 | 
						|
do_loop (void *user_data)
 | 
						|
{
 | 
						|
  PinosThreadMainLoopImpl *impl = user_data;
 | 
						|
  PinosThreadMainLoop *this = &impl->this;
 | 
						|
  SpaResult res;
 | 
						|
 | 
						|
  pthread_mutex_lock (&impl->lock);
 | 
						|
  pinos_log_debug ("thread-mainloop %p: enter thread", this);
 | 
						|
  pinos_loop_enter (this->loop);
 | 
						|
 | 
						|
  while (impl->running) {
 | 
						|
    if ((res = pinos_loop_iterate (this->loop, -1)) < 0)
 | 
						|
      pinos_log_warn ("thread-mainloop %p: iterate error %d", this, res);
 | 
						|
  }
 | 
						|
  pinos_log_debug ("thread-mainloop %p: leave thread", this);
 | 
						|
  pinos_loop_leave (this->loop);
 | 
						|
  pthread_mutex_unlock (&impl->lock);
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * pinos_thread_main_loop_start:
 | 
						|
 * @loop: a #PinosThreadMainLoop
 | 
						|
 *
 | 
						|
 * Start the thread to handle @loop.
 | 
						|
 *
 | 
						|
 * Returns: %SPA_RESULT_OK on success.
 | 
						|
 */
 | 
						|
SpaResult
 | 
						|
pinos_thread_main_loop_start (PinosThreadMainLoop *loop)
 | 
						|
{
 | 
						|
  PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this);
 | 
						|
 | 
						|
  if (!impl->running) {
 | 
						|
    int err;
 | 
						|
 | 
						|
    impl->running = true;
 | 
						|
    if ((err = pthread_create (&impl->thread, NULL, do_loop, impl)) != 0) {
 | 
						|
      pinos_log_warn ("thread-mainloop %p: can't create thread: %s", impl, strerror (err));
 | 
						|
      impl->running = false;
 | 
						|
      return SPA_RESULT_ERROR;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return SPA_RESULT_OK;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * pinos_thread_main_loop_stop:
 | 
						|
 * @loop: a #PinosThreadMainLoop
 | 
						|
 *
 | 
						|
 * Quit the main loop and stop its thread.
 | 
						|
 */
 | 
						|
void
 | 
						|
pinos_thread_main_loop_stop (PinosThreadMainLoop *loop)
 | 
						|
{
 | 
						|
  PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this);
 | 
						|
 | 
						|
  pinos_loop_signal_event (loop->loop, impl->event);
 | 
						|
 | 
						|
  pthread_join (impl->thread, NULL);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * pinos_thread_main_loop_lock:
 | 
						|
 * @loop: a #PinosThreadMainLoop
 | 
						|
 *
 | 
						|
 * Lock the mutex associated with @loop.
 | 
						|
 */
 | 
						|
void
 | 
						|
pinos_thread_main_loop_lock (PinosThreadMainLoop *loop)
 | 
						|
{
 | 
						|
  PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this);
 | 
						|
  pthread_mutex_lock (&impl->lock);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * pinos_thread_main_loop_unlock:
 | 
						|
 * @loop: a #PinosThreadMainLoop
 | 
						|
 *
 | 
						|
 * Unlock the mutex associated with @loop.
 | 
						|
 */
 | 
						|
void
 | 
						|
pinos_thread_main_loop_unlock (PinosThreadMainLoop *loop)
 | 
						|
{
 | 
						|
  PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this);
 | 
						|
  pthread_mutex_unlock (&impl->lock);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * pinos_thread_main_loop_signal:
 | 
						|
 * @loop: a #PinosThreadMainLoop
 | 
						|
 *
 | 
						|
 * Signal the main thread of @loop. If @wait_for_accept is %TRUE,
 | 
						|
 * this function waits until pinos_thread_main_loop_accept() is called.
 | 
						|
 */
 | 
						|
void
 | 
						|
pinos_thread_main_loop_signal (PinosThreadMainLoop *loop,
 | 
						|
                               bool                 wait_for_accept)
 | 
						|
{
 | 
						|
  PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this);
 | 
						|
 | 
						|
  if (impl->n_waiting > 0)
 | 
						|
    pthread_cond_broadcast (&impl->cond);
 | 
						|
 | 
						|
  if (wait_for_accept) {
 | 
						|
     impl->n_waiting_for_accept++;
 | 
						|
 | 
						|
     while (impl->n_waiting_for_accept > 0)
 | 
						|
       pthread_cond_wait (&impl->accept_cond, &impl->lock);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * pinos_thread_main_loop_wait:
 | 
						|
 * @loop: a #PinosThreadMainLoop
 | 
						|
 *
 | 
						|
 * Wait for the loop thread to call pinos_thread_main_loop_signal().
 | 
						|
 */
 | 
						|
void
 | 
						|
pinos_thread_main_loop_wait (PinosThreadMainLoop *loop)
 | 
						|
{
 | 
						|
  PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this);
 | 
						|
 | 
						|
  impl->n_waiting++;
 | 
						|
 | 
						|
  pthread_cond_wait (&impl->cond, &impl->lock);
 | 
						|
  impl->n_waiting --;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * pinos_thread_main_loop_accept:
 | 
						|
 * @loop: a #PinosThreadMainLoop
 | 
						|
 *
 | 
						|
 * Signal the loop thread waiting for accept with pinos_thread_main_loop_signal().
 | 
						|
 */
 | 
						|
void
 | 
						|
pinos_thread_main_loop_accept (PinosThreadMainLoop *loop)
 | 
						|
{
 | 
						|
  PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this);
 | 
						|
 | 
						|
  impl->n_waiting_for_accept--;
 | 
						|
  pthread_cond_signal (&impl->accept_cond);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * pinos_thread_main_loop_in_thread:
 | 
						|
 * @loop: a #PinosThreadMainLoop
 | 
						|
 *
 | 
						|
 * Check if we are inside the thread of @loop.
 | 
						|
 *
 | 
						|
 * Returns: %TRUE when called inside the thread of @loop.
 | 
						|
 */
 | 
						|
bool
 | 
						|
pinos_thread_main_loop_in_thread (PinosThreadMainLoop *loop)
 | 
						|
{
 | 
						|
  PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this);
 | 
						|
  return pthread_self() == impl->thread;
 | 
						|
}
 |