Files
jehanne/sys/src/kern/port/alloc.c
Giacomo Tesio c7d0f621c9 Clarify Forsyth's and 9front's copyrights
I'm very grateful to Charles Forsyth for creating most of Jehanne's kernel
and to 9front's guys for all the code and ideas they freely share.

Here I make their copyrights explicit as they had been erroneusly omitted
or messed up before. Sorry.
2018-01-05 02:30:45 +01:00

364 lines
7.0 KiB
C

/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
/* Portions of this file are Copyright (C) 2015-2018 Giacomo Tesio <giacomo@tesio.it>
* See /doc/license/gpl-2.0.txt for details about the licensing.
*/
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
#include <pool.h>
static void poolprint(Pool*, char*, ...);
static void ppanic(Pool*, char*, ...);
static void pool_lock(Pool*);
static void pool_unlock(Pool*);
typedef struct Private Private;
struct Private {
Lock lk;
char msg[256]; /* a rock for messages to be printed at unlock */
};
static Private pmainpriv;
static Pool pmainmem = {
.name= "Main",
.maxsize= 4*1024*1024,
.minarena= 128*1024,
.quantum= 32,
.alloc= xalloc,
.merge= xmerge,
.flags= POOL_TOLERANCE,
.lock= pool_lock,
.unlock= pool_unlock,
.print= poolprint,
.panic= ppanic,
.private= &pmainpriv,
};
static Private pimagpriv;
static Pool pimagmem = {
.name= "Image",
.maxsize= 16*1024*1024,
.minarena= 2*1024*1024,
.quantum= 32,
.alloc= xalloc,
.merge= xmerge,
.flags= 0,
.lock= pool_lock,
.unlock= pool_unlock,
.print= poolprint,
.panic= ppanic,
.private= &pimagpriv,
};
static Private psecrpriv;
static Pool psecrmem = {
.name= "Secrets",
.maxsize= 16*1024*1024,
.minarena= 64*1024,
.quantum= 32,
.alloc= xalloc,
.merge= xmerge,
.flags= POOL_ANTAGONISM,
.lock= pool_lock,
.unlock= pool_unlock,
.print= poolprint,
.panic= ppanic,
.private= &psecrpriv,
};
Pool* mainmem = &pmainmem;
Pool* imagmem = &pimagmem;
Pool* secrmem = &psecrmem;
/*
* because we can't print while we're holding the locks,
* we have the save the message and print it once we let go.
*/
static void
poolprint(Pool *p, char *fmt, ...)
{
va_list v;
Private *pv;
pv = p->private;
va_start(v, fmt);
vseprint(pv->msg+strlen(pv->msg), pv->msg+sizeof pv->msg, fmt, v);
va_end(v);
}
static void
ppanic(Pool *p, char *fmt, ...)
{
va_list v;
Private *pv;
char msg[sizeof pv->msg];
pv = p->private;
va_start(v, fmt);
vseprint(pv->msg+strlen(pv->msg), pv->msg+sizeof pv->msg, fmt, v);
va_end(v);
memmove(msg, pv->msg, sizeof msg);
iunlock(&pv->lk);
panic("%s", msg);
}
static void
pool_lock(Pool *p)
{
Private *pv;
pv = p->private;
ilock(&pv->lk);
// pv->lk.pc = getcallerpc();
pv->msg[0] = 0;
}
static void
pool_unlock(Pool *p)
{
Private *pv;
char msg[sizeof pv->msg];
pv = p->private;
if(pv->msg[0] == 0){
iunlock(&pv->lk);
return;
}
memmove(msg, pv->msg, sizeof msg);
iunlock(&pv->lk);
iprint("%.*s", sizeof pv->msg, msg);
}
void
poolsummary(Pool *p)
{
print("%s max %llud cur %llud free %llud alloc %llud\n", p->name,
(uint64_t)p->maxsize, (uint64_t)p->cursize,
(uint64_t)p->curfree, (uint64_t)p->curalloc);
}
void
mallocsummary(void)
{
poolsummary(mainmem);
poolsummary(imagmem);
poolsummary(secrmem);
}
/* everything from here down should be the same in libc, libdebugmalloc, and the kernel */
/* - except the code for malloc(), which alternately doesn't clear or does. */
/* - except the code for smalloc(), which lives only in the kernel. */
/*
* Npadlong is the number of uint32_t's to leave at the beginning of
* each allocated buffer for our own bookkeeping. We return to the callers
* a pointer that points immediately after our bookkeeping area. Incoming pointers
* must be decremented by that much, and outgoing pointers incremented.
* The malloc tag is stored at MallocOffset from the beginning of the block,
* and the realloc tag at ReallocOffset. The offsets are from the true beginning
* of the block, not the beginning the caller sees.
*
* The extra if(Npadlong != 0) in various places is a hint for the compiler to
* compile out function calls that would otherwise be no-ops.
*/
/* non tracing
*
enum {
Npadlong = 0,
MallocOffset = 0,
ReallocOffset = 0,
};
*
*/
/* tracing */
enum {
Npadlong = 2,
MallocOffset = 0,
ReallocOffset = 1
};
void*
smalloc(uint32_t size)
{
void *v;
while((v = poolalloc(mainmem, size+Npadlong*sizeof(uint32_t))) == nil){
if(!waserror()){
resrcwait(nil, nil);
poperror();
}
}
if(Npadlong){
v = (uint32_t*)v+Npadlong;
setmalloctag(v, getcallerpc());
}
memset(v, 0, size);
return v;
}
void*
jehanne_malloc(uint32_t size)
{
void *v;
v = poolalloc(mainmem, size+Npadlong*sizeof(uint32_t));
if(v == nil)
return nil;
if(Npadlong){
v = (uint32_t*)v+Npadlong;
setmalloctag(v, getcallerpc());
setrealloctag(v, 0);
}
memset(v, 0, size);
return v;
}
void*
jehanne_mallocz(uint32_t size, int clr)
{
void *v;
v = poolalloc(mainmem, size+Npadlong*sizeof(uint32_t));
if(Npadlong && v != nil){
v = (uint32_t*)v+Npadlong;
setmalloctag(v, getcallerpc());
setrealloctag(v, 0);
}
if(clr && v != nil)
memset(v, 0, size);
return v;
}
void*
jehanne_mallocalign(uint32_t size, uint32_t align, long offset, uint32_t span)
{
void *v;
v = poolallocalign(mainmem, size+Npadlong*sizeof(uint32_t), align, offset-Npadlong*sizeof(uint32_t), span);
if(Npadlong && v != nil){
v = (uint32_t*)v+Npadlong;
setmalloctag(v, getcallerpc());
setrealloctag(v, 0);
}
if(v)
memset(v, 0, size);
return v;
}
void
jehanne_free(void *v)
{
if(v != nil)
poolfree(mainmem, (uint32_t*)v-Npadlong);
}
void*
jehanne_realloc(void *v, uint32_t size)
{
void *nv;
if(v != nil)
v = (uint32_t*)v-Npadlong;
if(Npadlong !=0 && size != 0)
size += Npadlong*sizeof(uint32_t);
if(nv = poolrealloc(mainmem, v, size)){
nv = (uint32_t*)nv+Npadlong;
setrealloctag(nv, getcallerpc());
if(v == nil)
setmalloctag(nv, getcallerpc());
}
return nv;
}
uint32_t
jehanne_msize(void *v)
{
return poolmsize(mainmem, (uint32_t*)v-Npadlong)-Npadlong*sizeof(uint32_t);
}
/* secret memory, used to back cryptographic keys and cipher states */
void*
secalloc(uint32_t size)
{
void *v;
while((v = poolalloc(secrmem, size+Npadlong*sizeof(uint32_t))) == nil){
if(!waserror()){
resrcwait(nil, nil);
poperror();
}
}
if(Npadlong){
v = (uint32_t*)v+Npadlong;
setmalloctag(v, getcallerpc());
setrealloctag(v, 0);
}
memset(v, 0, size);
return v;
}
void
secfree(void *v)
{
if(v != nil)
poolfree(secrmem, (uint32_t*)v-Npadlong);
}
void
jehanne_setmalloctag(void *v, uintptr_t pc)
{
USED(v, pc);
if(Npadlong <= MallocOffset || v == nil)
return;
((uint32_t*)v)[-Npadlong+MallocOffset] = (uint32_t)pc;
}
void
jehanne_setrealloctag(void *v, uintptr_t pc)
{
USED(v, pc);
if(Npadlong <= ReallocOffset || v == nil)
return;
((uint32_t*)v)[-Npadlong+ReallocOffset] = (uint32_t)pc;
}
uintptr_t
jehanne_getmalloctag(void *v)
{
USED(v);
if(Npadlong <= MallocOffset)
return ~0;
return (int)((uint32_t*)v)[-Npadlong+MallocOffset];
}
uintptr_t
jehanne_getrealloctag(void *v)
{
USED(v);
if(Npadlong <= ReallocOffset)
return ~0;
return (int)((uint32_t*)v)[-Npadlong+ReallocOffset];
}