summaryrefslogblamecommitdiff
path: root/sos-code-article6.5/sos/kwaitq.h
blob: 4f879aa405a083fa153400c0b2c94da309262e47 (plain) (tree)



















































































































































































                                                                           
/* Copyright (C) 2004 David Decotigny

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.
   
   This program 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 General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
   USA. 
*/
#ifndef _SOS_KWAITQ_H_
#define _SOS_KWAITQ_H_

#include <sos/errno.h>
#include <sos/thread.h>
#include <sos/time.h>
#include <sos/sched.h>


/**
 * @kwaitq.h
 *
 * Low-level functions to manage queues of threads waiting for a
 * resource. These functions are public. For higher-level
 * synchronization primitives such as mutex, semaphores, conditions,
 * ... prefer looking at the corresponding libraries.
 */


/**
 * Define this if you want to know the names of the kwaitq
 */
// #define SOS_KWQ_DEBUG


/* Forward declaration */
struct sos_kwaitq_entry;


/**
 * Definition of a waitqueue. In a kwaitq, the threads are ordererd in
 * FIFO order.
 */
struct sos_kwaitq
{
#ifdef SOS_KWQ_DEBUG
# define SOS_KWQ_DEBUG_MAX_NAMELEN 32
  char name[SOS_KWQ_DEBUG_MAX_NAMELEN];
#endif
  struct sos_kwaitq_entry *waiting_list;
};


/**
 * Definition of an entry for a thread waiting in the waitqueue
 */
struct sos_kwaitq_entry
{
  /** The thread associted with this entry */
  struct sos_thread *thread;

  /** The kwaitqueue this entry belongs to */
  struct sos_kwaitq *kwaitq;

  /** TRUE when somebody woke up this entry */
  sos_bool_t wakeup_triggered;

  /** The status of wakeup for this entry. @see wakeup_status argument
      of sos_kwaitq_wakeup() */
  sos_ret_t wakeup_status;

  /** Other entries in this kwaitqueue */
  struct sos_kwaitq_entry *prev_entry_in_kwaitq, *next_entry_in_kwaitq;

  /** Other entries for the thread */
  struct sos_kwaitq_entry *prev_entry_for_thread, *next_entry_for_thread;  
};


/**
 * Initialize an empty waitqueue.
 *
 * @param name Used only if SOS_KWQ_DEBUG is defined (safe [deep
 * copied])
 */
sos_ret_t sos_kwaitq_init(struct sos_kwaitq *kwq,
			  const char *name);


/**
 * Release a waitqueue, making sure that no thread is in it.
 *
 * @return -SOS_EBUSY in case a thread is still in the waitqueue.
 */
sos_ret_t sos_kwaitq_dispose(struct sos_kwaitq *kwq);


/**
 * Return whether there are no threads in the waitq
 */
sos_bool_t sos_kwaitq_is_empty(const struct sos_kwaitq *kwq);


/**
 * Initialize a waitqueue entry. Mainly consists in updating the
 * "thread" field of the entry (set to current running thread), and
 * initializing the remaining of the entry as to indicate it does not
 * belong to any waitq.
 */
sos_ret_t sos_kwaitq_init_entry(struct sos_kwaitq_entry *kwq_entry);


/**
 * Add an entry (previously initialized with sos_kwaitq_init_entry())
 * in the given waitqueue.
 *
 * @note: No state change/context switch can occur here ! Among other
 * things: the current executing thread is not preempted.
 */
sos_ret_t sos_kwaitq_add_entry(struct sos_kwaitq *kwq,
			       struct sos_kwaitq_entry *kwq_entry);


/**
 * Remove the given kwaitq_entry from the kwaitq.
 *
 * @note: No state change/context switch can occur here ! Among other
 * things: the thread associated with the entry is not necessarilly
 * the same as the one currently running, and does not preempt the
 * current running thread if they are different.
 */
sos_ret_t sos_kwaitq_remove_entry(struct sos_kwaitq *kwq,
				  struct sos_kwaitq_entry *kwq_entry);


/**
 * Helper function to make the current running thread block in the
 * given kwaitq, waiting to be woken up by somedy else or by the given
 * timeout. It calls the sos_kwaitq_add_entry() and
 * sos_kwaitq_remove_entry().
 *
 * @param timeout The desired timeout (can be NULL => wait for
 * ever). It is updated by the function to reflect the remaining
 * timeout in case the thread has been woken-up prior to its
 * expiration.
 *
 * @return -SOS_EINTR when the thread is resumed while it has not be
 * explicitely woken up by someone calling sos_kwaitq_wakeup() upon
 * the same waitqueue... This can only happen 1/ if the timeout
 * expired, or 2/ if the current thread is also in another kwaitq
 * different to "kwq". Otherwise return the value set by
 * sos_kwaitq_wakeup(). The timeout remaining is updated in timeout.
 *
 * @note This is a BLOCKING FUNCTION
 */
sos_ret_t sos_kwaitq_wait(struct sos_kwaitq *kwq,
			  struct sos_time *timeout);


/**
 * Wake up as much as nb_thread threads (SOS_KWQ_WAKEUP_ALL to wake
 * up all threads) in the kwaitq kwq, in FIFO order.
 *
 * @param wakeup_status The value returned by sos_kwaitq_wait() when
 * the thread will effectively woken up due to this wakeup.
 */
sos_ret_t sos_kwaitq_wakeup(struct sos_kwaitq *kwq,
			    unsigned int nb_threads,
			    sos_ret_t wakeup_status);
#define SOS_KWQ_WAKEUP_ALL (~((unsigned int)0))


#endif /* _SOS_KWAITQ_H_ */