/*
 * sessn_gc.c
 *
 * x-kernel v3.3
 *
 * Copyright (c) 1993,1991,1990,1996  Arizona Board of Regents
 *
 * $Revision: 1.2 $
 * $Date: 1996/01/29 19:56:14 $
 */

/*
 * This garbage collector collects idle sessions.  See gc.h for the
 * interface.
 */

#include "xkernel.h"
#include "gc.h"

int tracesessngc = 0;

typedef struct {
    Map               map;
    u_int             interval;
    SessnGCDestructor destroy;
    char              *msg;
} CollectInfo;

#ifdef __STDC__

static int  markIdle(void *, void *, void *);
static void schedule(CollectInfo *);
static void sessnCollect(Event, void *);

#else

static int  markIdle();
static void schedule();
static void sessnCollect();

#endif /* __STDC__ */

static void
schedule(c)
CollectInfo *c;
{
    evDetach(evSchedule(sessnCollect, c, c->interval));
}

static int
markIdle(key, value, arg)
VOID *key;
VOID *value;
VOID *arg;
{
    Sessn       session = (Sessn)value;
    CollectInfo *c = (CollectInfo *)arg;
    int         retval = MFE_CONTINUE;

    if (session->rcnt == 0) {
	if (session->idle) {
	    xTrace2(sessngc, 5, "%s sessn GC closing %lx",
		    c->msg, (u_long)session);
	    session->binding = 0;
	    retval |= MFE_REMOVE;
	    c->destroy(session);
	}
	else {
	    xTrace2(sessngc, 5, "%s sessn GC marking %lx idle",
		    c->msg, (u_long)session);
	    session->idle = TRUE;
	}
    }
    else
	xTrace3(sessngc, 7, "%s session GC: %lx rcnt %d is not idle",
		c->msg, (u_long)session, session->rcnt);
    return retval;
}

static void
sessnCollect(ev, arg)
Event ev;
VOID  *arg;
{
    CollectInfo *c = (CollectInfo *)arg;

    xTrace1(sessngc, 3, "session garbage collector (%s)", c->msg);
    mapForEach(c->map, markIdle, c);
    schedule(c);
    xTrace1(sessngc, 5, "%s sessn GC exits", c->msg);
}


void
initSessionCollector(m, interval, destructor, msg)
Map               m;
int               interval;
SessnGCDestructor destructor;
char              *msg;
{
    CollectInfo *c;

    xTrace2(sessngc, 3,
	    "session garbage collector initialized for map %lx (%s)",
	    (u_long)m, msg ? msg : "");
    c = (CollectInfo *)xMalloc(sizeof(CollectInfo));
    c->map = m;
    c->interval = interval;
    c->destroy = destructor;
    c->msg = msg ? msg : "";
    schedule(c);
}
