minix/lib/libsys/asynsend.c
Ben Gras 68de328ac1 make the asynsend table size NPROCS-dependent.
this is a fix for e.g. the situation where lots of processes die
instantly, and PM has to send an asyn msg for each one to VFS, and
panics if there are too many. there are likely more situations in
which this table should be dependent on the no. of processes.

reported by pikpik on #minix3.
2010-10-01 14:39:04 +00:00

140 lines
2.6 KiB
C

#define _MINIX 1
#define _SYSTEM 1
#include <minix/config.h>
#include <ansi.h>
#include <assert.h>
#include <sys/types.h>
#include <minix/const.h>
#include <minix/type.h>
#include <stdlib.h>
#include <unistd.h>
#include <minix/syslib.h>
#include <minix/sysutil.h>
#include <minix/sys_config.h>
#include <limits.h>
#include <errno.h>
#define ASYN_NR (2*_NR_PROCS)
PRIVATE asynmsg_t msgtable[ASYN_NR];
PRIVATE int first_slot= 0, next_slot= 0;
PUBLIC int asynsend3(dst, mp, fl)
endpoint_t dst;
message *mp;
int fl;
{
int r, src_ind, dst_ind;
unsigned flags;
static int first = 1;
static int inside = 0;
int len;
/* printf() causes asynsend? */
if(inside) {
exit(1);
}
inside = 1;
if(first) {
int i;
for(i = 0; i < ASYN_NR; i++) {
msgtable[i].flags = AMF_EMPTY;
}
first = 0;
}
/* Update first_slot */
for (; first_slot < next_slot; first_slot++)
{
flags= msgtable[first_slot].flags;
if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE))
{
if (msgtable[first_slot].result != OK)
{
#if 0
printf(
"asynsend: found completed entry %d with error %d\n",
first_slot,
msgtable[first_slot].result);
#endif
}
continue;
}
if (flags != AMF_EMPTY)
break;
}
if (first_slot >= next_slot)
{
/* Reset first_slot and next_slot */
next_slot= first_slot= 0;
}
if (next_slot >= ASYN_NR)
{
/* Tell the kernel to stop processing */
r= senda(NULL, 0);
if (r != OK)
panic("asynsend: senda failed: %d", r);
dst_ind= 0;
for (src_ind= first_slot; src_ind<next_slot; src_ind++)
{
flags= msgtable[src_ind].flags;
if ((flags & (AMF_VALID|AMF_DONE)) ==
(AMF_VALID|AMF_DONE))
{
if (msgtable[src_ind].result != OK)
{
#if 0
printf(
"asynsend: found completed entry %d with error %d\n",
src_ind,
msgtable[src_ind].result);
#endif
}
continue;
}
if (flags == AMF_EMPTY)
continue;
#if 0
printf("asynsend: copying entry %d to %d\n",
src_ind, dst_ind);
#endif
if (src_ind != dst_ind)
msgtable[dst_ind]= msgtable[src_ind];
dst_ind++;
}
first_slot= 0;
next_slot= dst_ind;
if (next_slot >= ASYN_NR)
panic("asynsend: msgtable full");
}
fl |= AMF_VALID;
msgtable[next_slot].dst= dst;
msgtable[next_slot].msg= *mp;
msgtable[next_slot].flags= fl; /* Has to be last. The kernel
* scans this table while we
* are sleeping.
*/
next_slot++;
assert(first_slot < ASYN_NR);
assert(next_slot >= first_slot);
len = next_slot-first_slot;
assert(first_slot + len <= ASYN_NR);
/* Tell the kernel to rescan the table */
r = senda(msgtable+first_slot, len);
inside = 0;
return r;
}