summaryrefslogtreecommitdiff
path: root/sys/src/9/port/qio.c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2014-04-29 21:15:09 +0200
committercinap_lenrek <cinap_lenrek@felloff.net>2014-04-29 21:15:09 +0200
commitb7d8431036d1fbc8d366ef9ddff5e6ab93e4bc94 (patch)
treeb9e1dda3e41b474f28215706af1d8f4d3a1505a3 /sys/src/9/port/qio.c
parenta2f0fdbfa016157ee962947f4670ac37f7041508 (diff)
kernel: stop queue bloat before allocating blocks
Diffstat (limited to 'sys/src/9/port/qio.c')
-rw-r--r--sys/src/9/port/qio.c84
1 files changed, 46 insertions, 38 deletions
diff --git a/sys/src/9/port/qio.c b/sys/src/9/port/qio.c
index a70fa8a31..8076b04b8 100644
--- a/sys/src/9/port/qio.c
+++ b/sys/src/9/port/qio.c
@@ -1153,6 +1153,31 @@ qnotfull(void *a)
}
/*
+ * flow control, wait for queue to get below the limit
+ */
+static void
+qflow(Queue *q)
+{
+ for(;;){
+ if(q->noblock || qnotfull(q))
+ break;
+
+ ilock(q);
+ q->state |= Qflow;
+ iunlock(q);
+
+ eqlock(&q->wlock);
+ if(waserror()){
+ qunlock(&q->wlock);
+ nexterror();
+ }
+ sleep(&q->wr, qnotfull, q);
+ qunlock(&q->wlock);
+ poperror();
+ }
+}
+
+/*
* add a block to a queue obeying flow control
*/
long
@@ -1182,17 +1207,11 @@ qbwrite(Queue *q, Block *b)
}
/* don't queue over the limit */
- if(q->len >= q->limit){
- if(q->noblock){
- iunlock(q);
- freeb(b);
- poperror();
- return n;
- }
- if(q->len >= q->limit*10){
- iunlock(q);
- error(Egreg);
- }
+ if(q->len >= q->limit && q->noblock){
+ iunlock(q);
+ freeb(b);
+ poperror();
+ return n;
}
/* queue the block */
@@ -1228,34 +1247,13 @@ qbwrite(Queue *q, Block *b)
}
/*
- * flow control, wait for queue to get below the limit
- * before allowing the process to continue and queue
- * more. We do this here so that postnote can only
- * interrupt us after the data has been queued. This
- * means that things like 9p flushes and ssl messages
- * will not be disrupted by software interrupts.
- *
- * Note - this is moderately dangerous since a process
- * that keeps getting interrupted and rewriting will
- * queue up to 10 times the queue limit before failing.
+ * flow control, before allowing the process to continue and
+ * queue more. We do this here so that postnote can only
+ * interrupt us after the data has been queued. This means that
+ * things like 9p flushes and ssl messages will not be disrupted
+ * by software interrupts.
*/
- for(;;){
- if(q->noblock || qnotfull(q))
- break;
-
- ilock(q);
- q->state |= Qflow;
- iunlock(q);
-
- eqlock(&q->wlock);
- if(waserror()){
- qunlock(&q->wlock);
- nexterror();
- }
- sleep(&q->wr, qnotfull, q);
- qunlock(&q->wlock);
- poperror();
- }
+ qflow(q);
return n;
}
@@ -1273,6 +1271,16 @@ qwrite(Queue *q, void *vp, int len)
QDEBUG if(!islo())
print("qwrite hi %#p\n", getcallerpc(&q));
+ /* stop queue bloat before allocating blocks */
+ if(q->len/2 >= q->limit && q->noblock == 0 && q->bypass == nil){
+ while(waserror()){
+ if(up->procctl == Proc_exitme || up->procctl == Proc_exitbig)
+ error(Egreg);
+ }
+ qflow(q);
+ poperror();
+ }
+
sofar = 0;
do {
n = len-sofar;