/*static char *SCCSID = "@(#)placebuf.c 6.3 92/01/31";*/
#include <os2.h>
#include "const.h"
#include "misc.h"
#include "chain.h"
#include "buf.h"
#include "dir.h"
#include "volume.h"
#include "storage.h"
#include "tables.h"
#include "pb_ifs.h"
#include "superb.h"
#include "lw.h"
#include "frame.h"
#include "fsdata.h"
#include "assert.h"
#include "log.h"

#include "pr_CACHE.h"
#include "pr_MISC.h"
#include "pr_debug.h"



/*
 ***    PlaceBuf - Place buffer into LRU chain
 *
 *      PlaceBuf will place a particular buffer into the correct place
 *      in the LRU chain.  Not all buffer accesses demand that the buffer
 *      be put into the most-recently-used position.   For example, indirect
 *      blocks that are being freed are placed at the LRU position as they
 *      are not likely to be of use anymore.
 *
 *      The two complications we must address are:  what to do with placement
 *      of buffers that are not on the LRU list at all (recently filled,
 *      formerly free) and how to handle multiple sectors/buffer with each
 *      sector having a different "priority" for recycling.
 *
 *      Starting with the second complication, we have the principle that
 *      we may move a buffer to the MRU position, leave it alone, but place
 *      only formerly free buffers into the LRU position.
 *
 *      The first complication is easily solved.  Since the caller specifies
 *      the priority of the buffer, we may place a formerly free buffer as
 *      appropriate.  THIS IMPLMENTATION WILL NEVER PLACE A FORMERLY FREE
 *      BUFFER INTO THE LRU POSITION;  WE ALWAYS PLACE IT MRU.
 *
 *      ENTRY   pbuf = header address
 *              priBuf = advisory priority:
 *                          BP_KEEP - the buffer contains data that is likely
 *                              to be used in the near future
 *                          BP_NOOPINION - the buffer contains data that is
 *                              of questionable use
 *                          BP_TOSS - the buffer contains data is is not
 *                              going to be used again
 *
 *      EXIT    none
 *
 *      HISTORY
 * @76193   23-Nov-93 by D. Azzarito  - modify logging support for debug
 *          15-Sep-1988 16:32:54 by Bill McJohn [t-billm] Xlated from
 *                                      9/15/88 assembly code
 */

void
PlaceBuf (pbuf, priBuf)
PBUFNODE pbuf;      /*  address of buffer header to go into LRU chain  */
USHORT priBuf;      /*  advisory priority  */
{
//@76193 buffer isn't correct yet!     ASSERT_BUF (pbuf);

//    if (pbuf->bDirtMask)       /* keep dirty buffers off LRU chain */
//      return;

#ifdef DEBUG

    ChkHashChain ();

    /*  verify that priBuf has a legitimate value
     */
    if ((priBuf != BP_KEEP) &&
        (priBuf != BP_NOOPINION) &&
        (priBuf != BP_TOSS))

        INTERR ("PlaceBuf:  Bad Buffer Priority value.");

#endif

    /*  We've been entered with a buffer that may or may not be in the
     *  buffer list.  Depending on the type of placement desired, the buffer
     *  may be removed or added in other spots.  Note that we do this
     *  with a if-then-else dispatch rather than a switch statement.  The
     *  code is more efficient this way due to our ordering of the
     *  tests.
     */

    /*  If we might need the data in the near future
     */
    if (priBuf == BP_KEEP) {
        /*  If it's on the LRU list already
         *       remove it
         */
        if (pbuf->dcbpLru.pbufFwd != pbuf) {
            DCREM (pbuf, dcbpLru);
        }
        else
        /* If GFB is waiting for a free buffer, wake him up.
         * Note that it is okay to Wakeup here as long as wakeup
         * just marks the other processes ready but does not actually
         * cause a context switch.
         */
        if( pNoBufWaitChain != 0 ) {
            WakeupMisc2 (&(pNoBufWaitChain), LOB_NOBUF);
        }

          /*  Put in MRU position
           */
           DCADDF (pbuf, dcbpLru, bufLRUHead);
    }
    else
    /*  If we don't have an opinion about retaining the sector
     */
    if (priBuf == BP_NOOPINION) {
        /*  If it's not on the list then
         *      Add it at the LRU position
         */
        if (pbuf->dcbpLru.pbufFwd == pbuf) {
            DCADDB (pbuf, dcbpLru, bufLRUHead);
            /*  if GFB is waiting for a free buffer, wake him up
             */
            if( pNoBufWaitChain != 0 )
                WakeupMisc2 (&(pNoBufWaitChain), LOB_NOBUF);
        }
    }
    else {
        /*  priBuf == BP_TOSS.
         *
         * We won't use the cache buffer anytime soon.
         */

        /*  If it is on the LRU chain
         *      remove it
         */
        if (pbuf->dcbpLru.pbufFwd != pbuf) {
            DCREM (pbuf, dcbpLru);
        }
        else
        /*  if GFB is waiting for a free buffer, wake him up
         */
        if( pNoBufWaitChain != 0 ) {
            WakeupMisc2 (&(pNoBufWaitChain), LOB_NOBUF);
        }

        /*  Make buffer LRU (first to recycle)
         */
        DCADDB (pbuf, dcbpLru, bufLRUHead);

    }

}
