Add an InterruptDisabler helper class and use that for kmalloc.

The naive spinlock was not nearly enough to protect kmalloc from
reentrancy problems.

I don't want to deal with coming up with a fancy lock for kmalloc
right now, so I made an InterruptDisabler thingy instead.
It does CLI and then STI iff interrupts were previously enabled.
This commit is contained in:
Andreas Kling 2018-10-24 11:07:53 +02:00
parent 9a296d63f3
commit 0c5bbac86e
4 changed files with 35 additions and 14 deletions

View file

@ -18,7 +18,7 @@ bool ProcFileSystem::initialize()
{
SyntheticFileSystem::initialize();
addFile(createGeneratedFile("summary", [] {
cli();
InterruptDisabler disabler;
auto tasks = Task::allTasks();
char* buffer;
auto stringImpl = StringImpl::createUninitialized(tasks.size() * 128, buffer);
@ -36,7 +36,6 @@ bool ProcFileSystem::initialize()
}
ptr += ksprintf(ptr, "kmalloc: alloc: %u / free: %u\n", sum_alloc, sum_free);
*ptr = '\0';
sti();
return ByteBuffer::copy((byte*)buffer, ptr - buffer);
}));
return true;

View file

@ -185,7 +185,7 @@ Task* Task::create(const String& path, uid_t uid, gid_t gid)
if (!elfData)
return nullptr;
cli();
InterruptDisabler disabler; // FIXME: Get rid of this, jesus christ. This "critical" section is HUGE.
Task* t = new Task(parts.takeLast(), uid, gid);
ExecSpace space;
@ -218,7 +218,6 @@ Task* Task::create(const String& path, uid_t uid, gid_t gid)
#ifdef TASK_DEBUG
kprintf("Task %u (%s) spawned @ %p\n", t->pid(), t->name().characters(), t->m_tss.eip);
#endif
sti();
return t;
}
@ -461,11 +460,9 @@ void yield()
//kprintf("%s<%u> yield()\n", current->name().characters(), current->pid());
cli();
if (!scheduleNewTask()) {
sti();
InterruptDisabler disabler;
if (!scheduleNewTask())
return;
}
//kprintf("yield() jumping to new task: %x (%s)\n", current->farPtr().selector, current->name().characters());
switchNow();

View file

@ -79,6 +79,35 @@ void writeGDTEntry(WORD selector, Descriptor&);
#define cli() asm volatile("cli")
#define sti() asm volatile("sti")
static inline dword cpuFlags()
{
dword flags;
asm volatile(
"pushf\n"
"pop %0\n"
:"=rm"(flags)
::"memory");
return flags;
}
class InterruptDisabler {
public:
InterruptDisabler()
{
m_flags = cpuFlags();
cli();
}
~InterruptDisabler()
{
if (m_flags & 0x200)
sti();
}
private:
dword m_flags;
};
/* Map IRQ0-15 @ ISR 0x50-0x5F */
#define IRQ_VECTOR_BASE 0x50

View file

@ -10,7 +10,6 @@
#include "VGA.h"
#include "system.h"
#include "Assertions.h"
#include <AK/Lock.h>
#define SANITIZE_KMALLOC
@ -30,12 +29,9 @@ PRIVATE BYTE alloc_map[POOL_SIZE / CHUNK_SIZE / 8];
volatile DWORD sum_alloc = 0;
volatile DWORD sum_free = POOL_SIZE;
static SpinLock s_kmallocLock;
PUBLIC void
kmalloc_init()
{
s_kmallocLock.init();
memset( &alloc_map, 0, sizeof(alloc_map) );
memset( (void *)BASE_PHYS, 0, POOL_SIZE );
@ -46,7 +42,7 @@ kmalloc_init()
PUBLIC void *
kmalloc( DWORD size )
{
Locker locker(s_kmallocLock);
InterruptDisabler disabler;
DWORD chunks_needed, chunks_here, first_chunk;
DWORD real_size;
@ -123,7 +119,7 @@ kfree( void *ptr )
if( !ptr )
return;
Locker locker(s_kmallocLock);
InterruptDisabler disabler;
allocation_t *a = (allocation_t *)((((BYTE *)ptr) - sizeof(allocation_t)));