shithub: asif

Download patch

ref: 6cea0ac16962d9de3004a751302dc743c321fa95
parent: af76a32eea6c19a5f608680f37bfc5e370a2ab36
author: qwx <qwx@sciops.net>
date: Sat Jun 4 08:20:20 EDT 2022

zalloc: hide implementation and add checks

really complicated now

--- a/asif.h
+++ b/asif.h
@@ -106,19 +106,13 @@
 void*	emalloc(ulong);
 
 typedef struct Zpool Zpool;
-typedef struct Znode Znode;
-struct Znode{
-	Znode *next;
-	Znode *prev;
+struct Zpool{
+	usize elsize;
 	void data[];
 };
-struct Zpool{
-	int elsize;
-	Znode;
-};
-void	zfree(Znode*, Zpool*);
+void	zfree(void*);
 void*	zalloc(Zpool*);
-Zpool*	znew(int);
+Zpool*	znew(usize);
 
 #define MIN(a,b)	((a) <= (b) ? (a) : (b))
 #define MAX(a,b)	((a) >= (b) ? (a) : (b))
--- a/zalloc.c
+++ b/zalloc.c
@@ -2,15 +2,65 @@
 #include <libc.h>
 #include "asif.h"
 
-/* no nodes are ever freed, left to be reclaimed by the kernel on exit */
+/* no nodes are ever freed, left to be reclaimed by the kernel on exit
+ * got more complicated, but should be able to detect some bugs...
+ * unsuitable for very large collections probably */
+
+typedef struct Zhouse Zhouse;
+typedef struct Znode Znode;
+typedef struct Zhdr Zhdr;
+typedef struct Ztail Ztail;
+struct Zhdr{
+	Zhouse *z;
+	Znode *next;
+	Znode *prev;
+};
+struct Znode{
+	Zhdr;
+	void data[];
+};
+struct Ztail{
+	Zpool *z;
+};
+struct Zhouse{
+	Zpool;
+	Znode;
+};
+
 enum{
 	Ninc = 128,
 };
 
+static Ztail *
+n2t(Znode *p)
+{
+	return (Ztail *)((uchar *)p + sizeof(Zhdr) + p->z->elsize);
+}
+
+static Znode *
+v2n(uchar *data)
+{
+	return (Znode *)(data - sizeof(Zhdr));
+}
+
 static void
-zlink(Znode *p, Zpool *z)
+zcheckpool(Znode *p, Zhouse *z)
 {
-	assert(p != nil && z != nil);
+	Ztail *t;
+
+	assert(p == nil || p != z);
+	assert(z != nil && z->elsize > 0);
+	if(p != nil){
+		assert(p->z == z);
+		t = n2t(p);
+		assert(t->z == z);
+	}
+}
+
+static void
+zlink(Znode *p, Zhouse *z)
+{
+	zcheckpool(p, z);
 	p->prev = z->prev;
 	p->next = &z->Znode;
 	z->prev->next = p;
@@ -18,57 +68,78 @@
 }
 
 static Znode *
-zunlink(Zpool *z)
+zpop(Zhouse *z)
 {
-	Znode *q;
+	Znode *p;
 
-	assert(z != nil && z->next != nil);
-	q = z->next;
-	q->next->prev = &z->Znode;
-	z->next = q->next;
-	q->prev = q->next = nil;
-	return q;
+	p = z->next;
+	assert(p != z);
+	zcheckpool(p, z);
+	p->next->prev = &z->Znode;
+	z->next = p->next;
+	p->prev = p->next = nil;
+	return p;
 }
 
 static void
-zfeed(Zpool *z)
+_zfree(Znode *p)
 {
-	int n;
-	uchar *p, *q;
+	Zhouse *z;
 
-	assert(z != nil && z->elsize > 0);
-	if(z->next != z)
+	if(p == nil)
 		return;
-	n = z->elsize + sizeof *z;
-	p = emalloc(Ninc * n);		// see comment
-	for(q=p; q<p+Ninc*n; q+=n)
-		zlink((Znode*)q, z);
+	z = p->z;
+	zcheckpool(p, z);
+	memset(p->data, 0, z->elsize);
+	zlink(p, z);
 }
 
 void
-zfree(Znode *p, Zpool *z)
+zfree(void *data)
 {
-	if(p == nil)
+	if(data == nil)
 		return;
-	assert(z != nil);
-	memset(p->data, 0, z->elsize);
-	zlink(p, z);
+	_zfree(v2n(data));
 }
 
+static void
+zfeed(Zhouse *z)
+{
+	ulong n;
+	uchar *u, *v;
+	Znode *p;
+	Ztail *t;
+
+	if(z->next != z)
+		return;
+	zcheckpool(nil, z);
+	n = sizeof(Zhdr) + z->elsize + sizeof *t;
+	u = emalloc(Ninc * n);
+	for(v=u; v<u+Ninc*n; v+=n){
+		p = (Znode *)v;
+		t = n2t(p);
+		p->z = z->z;
+		t->z = z->z;
+		zlink(p, z);
+	}
+}
+
 void *
-zalloc(Zpool *z)
+zalloc(Zpool *zp)
 {
 	Znode *p;
+	Zhouse *z;
 
+	z = (Zhouse *)zp;
 	zfeed(z);
-	p = zunlink(z);
+	p = zpop(z);
 	return p->data;
 }
 
 Zpool *
-znew(int elsize)
+znew(usize elsize)
 {
-	Zpool *z;
+	Zhouse *z;
 
 	assert(elsize > 0);
 	z = emalloc(sizeof *z);