code: plan9front

Download patch

ref: 3e115487969570445a58a5a351a7bf0e0ab5fc21
parent: 99529b80a3bbe35c5cd5dadf5f106632a2449e84
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Sep 3 13:30:04 EDT 2022

kernel: half NERR, refcount Note's to avoid excessive allocations for postnotepg()

Half NERR stack to 32.

When posing a note to a large group, avoid allocating Notes
for each individual process, but post the reference instread.

factor out process interruption into procinterrupt().

Avoid allocation of notes in alarmkproc, just posting the
same note to everyone.

--- a/sys/src/9/port/alarm.c
+++ b/sys/src/9/port/alarm.c
@@ -27,7 +27,13 @@
 			if(!canqlock(&rp->debug))
 				break;
 			if(rp->alarm != 0){
-				postnote(rp, 0, "alarm", NUser);
+				static Note alarm = {
+					"alarm",
+					NUser,
+					1,
+				};
+				incref(&alarm);
+				pushnote(rp, &alarm);
 				rp->alarm = 0;
 			}
 			qunlock(&rp->debug);
--- a/sys/src/9/port/devproc.c
+++ b/sys/src/9/port/devproc.c
@@ -351,24 +351,6 @@
 	error(Eperm);
 }
 
-static void
-postnotepg(ulong noteid, char *n, int flag)
-{
-	Proc *p;
-	int i;
-
-	for(i = 0; (p = proctab(i)) != nil; i++){
-		if(p == up)
-			continue;
-		if(p->noteid != noteid || p->kp)
-			continue;
-		qlock(&p->debug);
-		if(p->noteid == noteid)
-			postnote(p, 0, n, flag);
-		qunlock(&p->debug);
-	}
-}
-
 static void clearwatchpt(Proc *p);
 
 static Chan*
@@ -1421,6 +1403,12 @@
 static void
 procctlreq(Proc *p, char *va, int n)
 {
+	static Note killnote = {
+		"sys: killed",
+		NExit,
+		1,
+	};
+
 	Segment *s;
 	uintptr npc;
 	int pri;
@@ -1455,12 +1443,14 @@
 			break;
 		case Stopped:
 			p->procctl = Proc_exitme;
-			postnote(p, 0, "sys: killed", NExit);
+			incref(&killnote);
+			pushnote(p, &killnote);
 			ready(p);
 			break;
 		default:
 			p->procctl = Proc_exitme;
-			postnote(p, 0, "sys: killed", NExit);
+			incref(&killnote);
+			pushnote(p, &killnote);
 		}
 		break;
 	case CMnohang:
@@ -1542,7 +1532,7 @@
 		}
 		break;
 	case CMinterrupt:
-		postnote(p, 0, nil, NUser);
+		procinterrupt(p);
 		break;
 	case CMnointerrupt:
 		if(p->nnote == 0)
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -314,6 +314,7 @@
 {
 	char	msg[ERRMAX];
 	int	flag;			/* whether system posted it */
+	Ref;
 };
 
 enum
@@ -629,7 +630,7 @@
 	TCSys,
 	TCReal,
 
-	NERR = 64,
+	NERR = 32,
 	NNOTE = 5,
 
 	Npriq		= 20,		/* number of scheduler priority levels */
@@ -714,7 +715,7 @@
 	int	procctl;	/* Control for /proc debugging */
 	uintptr	pc;		/* DEBUG only */
 
-	Lock	rlock;		/* sync sleep/wakeup with postnote */
+	Lock	rlock;		/* sync sleep/wakeup with procinterrupt */
 	Rendez	*r;		/* rendezvous point slept on */
 	Rendez	sleep;		/* place for syssleep/debug */
 	int	notepending;	/* note issued but not acted on */
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -121,6 +121,7 @@
 void		freeb(Block*);
 void		freeblist(Block*);
 int		freebroken(void);
+void		freenote(Note*);
 void		freenotes(Proc*);
 void		freepages(Page*, Page*, ulong);
 void		freepte(Segment*, Pte*);
@@ -238,6 +239,7 @@
 void		portcountpagerefs(ulong*, int);
 char*		popnote(Ureg*);
 int		postnote(Proc*, int, char*, int);
+void		postnotepg(ulong, char*, int);
 int		pprint(char*, ...);
 int		preempted(void);
 void		prflush(void);
@@ -250,6 +252,7 @@
 void		procflushothers(void);
 int		procindex(ulong);
 void		procinit0(void);
+void		procinterrupt(Proc*);
 ulong		procpagecount(Proc*);
 void		procpriority(Proc*, int, int);
 void		procsetuser(char*);
@@ -261,6 +264,7 @@
 int		pullblock(Block**, int);
 Block*		pullupblock(Block*, int);
 Block*		pullupqueue(Queue*, int);
+int		pushnote(Proc*, Note*);
 void		putimage(Image*);
 void		putmhead(Mhead*);
 void		putmmu(uintptr, uintptr, Page*);
--- a/sys/src/9/port/proc.c
+++ b/sys/src/9/port/proc.c
@@ -899,51 +899,6 @@
 }
 
 /*
- *  pop a note from the calling process or suicide if theres
- *  no note handler or notify during note handling. 
- *  Called from notify() with up->debug lock held.
- */
-char*
-popnote(Ureg *u)
-{
-	assert(!canqlock(&up->debug));
-
-	up->notepending = 0;
-	if(up->nnote == 0)
-		return nil;
-	assert(up->nnote > 0);
-	assert(up->note[0] != nil);
-
-	/* hold off user notes during note handling */
-	if(up->notified && up->note[0]->flag == NUser)
-		return nil;
-
-	free(up->lastnote);
-	up->lastnote = up->note[0];
-	if(--up->nnote > 0)
-		memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note*));
-	up->note[up->nnote] = nil;
-
-	if(u != nil && strncmp(up->lastnote->msg, "sys:", 4) == 0){
-		int l = strlen(up->lastnote->msg);
-		assert(l < ERRMAX);
-		snprint(up->lastnote->msg+l, ERRMAX-l, " pc=%#p", u->pc);
-	}
-
-	if(up->notify == nil || up->notified){
-		qunlock(&up->debug);
-		if(up->lastnote->flag == NDebug){
-			up->fpstate &= ~FPillegal;
-			pprint("suicide: %s\n", up->lastnote->msg);
-		}
-		pexit(up->lastnote->msg, up->lastnote->flag!=NDebug);
-	}
-	up->notified = 1;
-
-	return up->lastnote->msg;
-}
-
-/*
  *  if waking a sleeping process, this routine must hold both
  *  p->rlock and r->lock.  However, it can't know them in
  *  the same order as wakeup causing a possible lock ordering
@@ -950,45 +905,13 @@
  *  deadlock.  We break the deadlock by giving up the p->rlock
  *  lock if we can't get the r->lock and retrying.
  */
-int
-postnote(Proc *p, int dolock, char *msg, int flag)
+void
+procinterrupt(Proc *p)
 {
-	int s, ret;
 	QLock *q;
-	Note *n;
+	int s;
 
-	if(p == nil)
-		return 0;
-
-	if(dolock)
-		qlock(&p->debug);
-
-	if(p->pid == 0){
-		if(dolock)
-			qunlock(&p->debug);
-		return 0;
-	}
-
-	ret = 0;
-	if(msg != nil){
-		if(flag != NUser && (p->notify == nil || p->notified))
-			freenotes(p);
-		if(p->nnote < NNOTE){
-			if(flag != NUser)
-				n = smalloc(sizeof(Note));
-			else
-				n = malloc(sizeof(Note));
-			if(n != nil){
-				kstrcpy(n->msg, msg, ERRMAX);
-				n->flag = flag;
-				p->note[p->nnote++] = n;
-				ret = 1;
-			}
-		}
-	}
 	p->notepending = 1;
-	if(dolock)
-		qunlock(&p->debug);
 
 	/* this loop is to avoid lock ordering problems. */
 	for(;;){
@@ -1005,7 +928,7 @@
 		/* try for the second lock */
 		if(canlock(r)){
 			if(p->state != Wakeme || r->p != p)
-				panic("postnote: state %d %d %d", r->p != p, p->r != r, p->state);
+				panic("procinterrupt: state %d %d %d", r->p != p, p->r != r, p->state);
 			p->r = nil;
 			r->p = nil;
 			ready(p);
@@ -1067,9 +990,125 @@
 		unlock(p->rgrp);
 		break;
 	}
+}
+
+/*
+ *  pop a note from the calling process or suicide if theres
+ *  no note handler or notify during note handling. 
+ *  Called from notify() with up->debug lock held.
+ */
+char*
+popnote(Ureg *u)
+{
+	up->notepending = 0;
+	if(up->nnote == 0)
+		return nil;
+	assert(up->nnote > 0);
+	assert(up->note[0] != nil);
+	assert(up->note[0]->ref > 0);
+
+	/* hold off user notes during note handling */
+	if(up->notified && up->note[0]->flag == NUser)
+		return nil;
+
+	freenote(up->lastnote);
+	up->lastnote = up->note[0];
+	if(--up->nnote > 0)
+		memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note*));
+	up->note[up->nnote] = nil;
+
+	if(u != nil && up->lastnote->ref == 1 && strncmp(up->lastnote->msg, "sys:", 4) == 0){
+		int l = strlen(up->lastnote->msg);
+		assert(l < ERRMAX);
+		snprint(up->lastnote->msg+l, ERRMAX-l, " pc=%#p", u->pc);
+	}
+
+	if(up->notify == nil || up->notified){
+		qunlock(&up->debug);
+		if(up->lastnote->flag == NDebug){
+			up->fpstate &= ~FPillegal;
+			pprint("suicide: %s\n", up->lastnote->msg);
+		}
+		pexit(up->lastnote->msg, up->lastnote->flag!=NDebug);
+	}
+	up->notified = 1;
+
+	return up->lastnote->msg;
+}
+
+static Note*
+mknote(char *msg, int flag)
+{
+	Note *n;
+
+	n = smalloc(sizeof(Note));
+	kstrcpy(n->msg, msg, ERRMAX);
+	n->flag = flag;
+	n->ref = 1;
+	return n;
+}
+
+int
+pushnote(Proc *p, Note *n)
+{
+	if(p->pid == 0){
+		freenote(n);
+		return 0;
+	}
+	assert(n->ref > 0);
+	if(n->flag != NUser && (p->notify == nil || p->notified))
+		freenotes(p);
+	if(p->nnote < NNOTE){
+		p->note[p->nnote++] = n;
+		procinterrupt(p);
+		return 1;
+	}
+	freenote(n);
+	return 0;
+}
+
+int
+postnote(Proc *p, int dolock, char *msg, int flag)
+{
+	Note *n;
+	int ret;
+
+	if(p == nil)
+		return 0;
+
+	n = mknote(msg, flag);
+	if(dolock)
+		qlock(&p->debug);
+	ret = pushnote(p, n);
+	if(dolock)
+		qunlock(&p->debug);
+
 	return ret;
 }
 
+void
+postnotepg(ulong noteid, char *msg, int flag)
+{
+	Note *n;
+	Proc *p;
+	int i;
+
+	n = mknote(msg, flag);
+	for(i = 0; (p = proctab(i)) != nil; i++){
+		if(p == up)
+			continue;
+		if(p->noteid != noteid || p->kp)
+			continue;
+		qlock(&p->debug);
+		if(p->noteid == noteid){
+			incref(n);
+			pushnote(p, n);
+		}
+		qunlock(&p->debug);
+	}
+	freenote(n);
+}
+
 /*
  * weird thing: keep at most NBROKEN around
  */
@@ -1133,10 +1172,18 @@
 }
 
 void
+freenote(Note *n)
+{
+	if(n == nil || decref(n))
+		return;
+	free(n);
+}
+
+void
 freenotes(Proc *p)
 {
 	while(p->nnote > 0){
-		free(p->note[--p->nnote]);
+		freenote(p->note[--p->nnote]);
 		up->note[p->nnote] = nil;
 	}
 }
@@ -1253,7 +1300,7 @@
 	}
 
 	freenotes(up);
-	free(up->lastnote);
+	freenote(up->lastnote);
 	up->lastnote = nil;
 	up->notified = 0;
 
--- a/sys/src/9/port/sysproc.c
+++ b/sys/src/9/port/sysproc.c
@@ -600,7 +600,7 @@
 	up->setargs = 0;
 
 	freenotes(up);
-	free(up->lastnote);
+	freenote(up->lastnote);
 	up->lastnote = nil;
 	up->notify = nil;
 	up->notified = 0;