172 lines
2.7 KiB
C
172 lines
2.7 KiB
C
#include "stdinc.h"
|
|
#include "dat.h"
|
|
#include "fns.h"
|
|
|
|
typedef struct LumpQueue LumpQueue;
|
|
typedef struct WLump WLump;
|
|
|
|
enum
|
|
{
|
|
MaxLumpQ = 1 << 3 /* max. lumps on a single write queue, must be pow 2 */
|
|
};
|
|
|
|
struct WLump
|
|
{
|
|
Lump *u;
|
|
Packet *p;
|
|
int creator;
|
|
int gen;
|
|
uint ms;
|
|
};
|
|
|
|
struct LumpQueue
|
|
{
|
|
QLock lock;
|
|
Rendez flush;
|
|
Rendez full;
|
|
Rendez empty;
|
|
WLump q[MaxLumpQ];
|
|
int w;
|
|
int r;
|
|
};
|
|
|
|
static LumpQueue *lumpqs;
|
|
static int nqs;
|
|
|
|
static QLock glk;
|
|
static int gen;
|
|
|
|
static void queueproc(void *vq);
|
|
|
|
int
|
|
initlumpqueues(int nq)
|
|
{
|
|
LumpQueue *q;
|
|
|
|
int i;
|
|
nqs = nq;
|
|
|
|
lumpqs = MKNZ(LumpQueue, nq);
|
|
|
|
for(i = 0; i < nq; i++){
|
|
q = &lumpqs[i];
|
|
q->full.l = &q->lock;
|
|
q->empty.l = &q->lock;
|
|
q->flush.l = &q->lock;
|
|
|
|
if(vtproc(queueproc, q) < 0){
|
|
seterr(EOk, "can't start write queue slave: %r");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* queue a lump & it's packet data for writing
|
|
*/
|
|
int
|
|
queuewrite(Lump *u, Packet *p, int creator, uint ms)
|
|
{
|
|
LumpQueue *q;
|
|
int i;
|
|
|
|
trace(TraceProc, "queuewrite");
|
|
i = indexsect(mainindex, u->score);
|
|
if(i < 0 || i >= nqs){
|
|
seterr(EBug, "internal error: illegal index section in queuewrite");
|
|
return -1;
|
|
}
|
|
|
|
q = &lumpqs[i];
|
|
|
|
qlock(&q->lock);
|
|
while(q->r == ((q->w + 1) & (MaxLumpQ - 1))){
|
|
trace(TraceProc, "queuewrite sleep");
|
|
rsleep(&q->full);
|
|
}
|
|
|
|
q->q[q->w].u = u;
|
|
q->q[q->w].p = p;
|
|
q->q[q->w].creator = creator;
|
|
q->q[q->w].ms = ms;
|
|
q->q[q->w].gen = gen;
|
|
q->w = (q->w + 1) & (MaxLumpQ - 1);
|
|
|
|
trace(TraceProc, "queuewrite wakeup");
|
|
rwakeup(&q->empty);
|
|
|
|
qunlock(&q->lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
flushqueue(void)
|
|
{
|
|
int i;
|
|
LumpQueue *q;
|
|
|
|
if(!lumpqs)
|
|
return;
|
|
|
|
trace(TraceProc, "flushqueue");
|
|
|
|
qlock(&glk);
|
|
gen++;
|
|
qunlock(&glk);
|
|
|
|
for(i=0; i<mainindex->nsects; i++){
|
|
q = &lumpqs[i];
|
|
qlock(&q->lock);
|
|
while(q->w != q->r && gen - q->q[q->r].gen > 0){
|
|
trace(TraceProc, "flushqueue sleep q%d", i);
|
|
rsleep(&q->flush);
|
|
}
|
|
qunlock(&q->lock);
|
|
}
|
|
}
|
|
|
|
static void
|
|
queueproc(void *vq)
|
|
{
|
|
LumpQueue *q;
|
|
Lump *u;
|
|
Packet *p;
|
|
int creator;
|
|
uint ms;
|
|
|
|
threadsetname("queueproc");
|
|
|
|
q = vq;
|
|
for(;;){
|
|
qlock(&q->lock);
|
|
while(q->w == q->r){
|
|
trace(TraceProc, "queueproc sleep empty");
|
|
rsleep(&q->empty);
|
|
}
|
|
|
|
u = q->q[q->r].u;
|
|
p = q->q[q->r].p;
|
|
creator = q->q[q->r].creator;
|
|
ms = q->q[q->r].ms;
|
|
|
|
q->r = (q->r + 1) & (MaxLumpQ - 1);
|
|
trace(TraceProc, "queueproc wakeup flush");
|
|
rwakeupall(&q->flush);
|
|
|
|
trace(TraceProc, "queueproc wakeup full");
|
|
rwakeup(&q->full);
|
|
|
|
qunlock(&q->lock);
|
|
|
|
trace(TraceProc, "queueproc writelump %V", u->score);
|
|
if(writeqlump(u, p, creator, ms) < 0)
|
|
fprint(2, "failed to write lump for %V: %r", u->score);
|
|
trace(TraceProc, "queueproc wrotelump %V", u->score);
|
|
|
|
putlump(u);
|
|
}
|
|
}
|