/*     
 * $RCSfile: shepherd_pool.h,v $
 *
 * x-kernel v3.3
 *
 * Copyright (c) 1993,1991,1990,1996  Arizona Board of Regents
 *
 * $Log: shepherd_pool.h,v $
 * Revision 1.1  1997/03/11  20:47:08  dorgival
 * Initial revision
 *
 * Revision 1.1  1997/03/11 20:47:08  dorgival
 * Initial revision
 *
 *
 */
/*
 * shepherd_pool implements a pool of msgs which can be used by a device driver
 * main receiving thread to communicate with shepherd threads. The first
 * attempt is guided by the hippi out-of-kernel device driver, but it should
 * be pretty independent of it.
 */
#ifndef __shepherd_pool_h__
#define __shepherd_pool_h__

/*
 * The idea of the pool is that messages are being received/constructed
 * by a device driver main loop, and they must be passed to shepherd
 * threads. The pool is initialized with a certain number of initial
 * msg holders and some shepherd threads. Limits as to the maximum number
 * of both are also defined.
 *
 * The operations are, then:
 *
 * - get an free msg holder: Executed by the device loop each time a
 *   packet is received. If no free holders are available, a new one
 *   is created, as long as the limit is not reached. If that happens,
 *   new requests get no holder, what will probably mean messages will
 *   be dropped.
 * - enqueue a msg descriptor: Once the message is built, it must be
 *   enqueued so that shepherd threads may access it. To guarantee
 *   fast processing, it may be interesting to create a new shepherd
 *   thread if none is idle by the time a msg is enqueued. A limit
 *   may also be set in this case.
 * - get a msg descriptor: Executed by each shepherd to start a processing
 *   cycle. If no messages are available, the thread must block until
 *   one arrives.
 * - release a free holder: Once a message is processed by the
 *   shepherd thread, its holder may be put back in the pool, so it
 *   may be reused by the device.
 *
 * These operations are implemented in the functions below.
 */

#include "msg.h"
#include "xk_fifo.h"

/*
 * In msg_holder, the first field has to be the next pointer, so it
 * can be typecast to FIFOEl without any problems.
 */

typedef void (*shepherd_func_t)(void* arg, Msg* msg);

typedef struct msg_holder {
    struct msg_holder* next;
    Msg msg;
} msg_holder_t;

typedef struct {
    xk_fifo_t       free_holders;
    int             holder_low_limit;
    int             holder_cnt;
    int             holder_high_limit;
    xk_fifo_t       shepherd_queue;
    shepherd_func_t shepherd;
    void*           arg;
    int             shepherd_low_limit;
    int             shepherd_cnt;
    int             shepherd_high_limit;
} shepherd_pool_t;

extern shepherd_pool_t*
       shepherd_pool_init( shepherd_pool_t* pool,
	                   int              holder_low_limit,
			   int              holder_high_limit,
		           shepherd_func_t  shepherd,
			   void*            arg,
		           int              shepherd_low_limit,
			   int              shepherd_high_limit );

extern msg_holder_t* get_free_holder( shepherd_pool_t* pool );
extern void          trigger_shepherd( shepherd_pool_t* pool,msg_holder_t* h);

#endif /* __shepherd_pool_h__ */
