217 lines
6.6 KiB
C
217 lines
6.6 KiB
C
|
/* 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>
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @kwaitq.h
|
||
|
*
|
||
|
* Low-level functions to manage queues of threads waiting for a
|
||
|
* resource. These functions are public, except
|
||
|
* sos_kwaitq_change_priority() that is a callback for the thread
|
||
|
* subsystem. However, for higher-level synchronization primitives
|
||
|
* such as mutex, semaphores, conditions, ... prefer to look 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;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* The threads in the kwaitqs can be ordered in FIFO or in decreasing
|
||
|
* priority order.
|
||
|
*/
|
||
|
typedef enum { SOS_KWQ_ORDER_FIFO, SOS_KWQ_ORDER_PRIO } sos_kwaitq_ordering_t;
|
||
|
|
||
|
|
||
|
#include <sos/sched.h>
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Definition of a waitqueue. In a kwaitq, the threads can be ordererd
|
||
|
* either in FIFO order (SOS_KWQ_ORDER_FIFO) or in decreasing priority
|
||
|
* order (SOS_KWQ_ORDER_PRIO ; with FIFO ordering for same-prio
|
||
|
* threads).
|
||
|
*
|
||
|
* A more efficient method to store the threads ordered by their
|
||
|
* priority would have been to use 1 list for each priority level. But
|
||
|
* we have to be careful to the size of a kwaitq structure here:
|
||
|
* potentially there are thousands of kwaitq in a running system
|
||
|
* (basically: 1 per opened file !). The algorithm we use to order the
|
||
|
* threads in the kwaitq in this case is highly under-optimal (naive
|
||
|
* linear insertion): as an exercise, one can implement a more
|
||
|
* efficient algorithm (think of a heap).
|
||
|
*/
|
||
|
struct sos_kwaitq
|
||
|
{
|
||
|
#ifdef SOS_KWQ_DEBUG
|
||
|
# define SOS_KWQ_DEBUG_MAX_NAMELEN 32
|
||
|
char name[SOS_KWQ_DEBUG_MAX_NAMELEN];
|
||
|
#endif
|
||
|
sos_kwaitq_ordering_t ordering;
|
||
|
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,
|
||
|
sos_kwaitq_ordering_t ordering);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* 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 or decreasing priority
|
||
|
* order (depends on the ordering scheme selected at kwaitq
|
||
|
* initialization time).
|
||
|
*
|
||
|
* @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))
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @note INTERNAL function (in particular: interrupts not disabled) !
|
||
|
*
|
||
|
* @note: The use of this function is RESERVED (to thread.c). Do not
|
||
|
* call it directly: use sos_thread_set_priority() for that !
|
||
|
*/
|
||
|
sos_ret_t sos_kwaitq_change_priority(struct sos_kwaitq *kwq,
|
||
|
struct sos_kwaitq_entry *kwq_entry,
|
||
|
sos_sched_priority_t priority);
|
||
|
|
||
|
#endif /* _SOS_KWAITQ_H_ */
|