diff --git a/sortix/Makefile b/sortix/Makefile
index c50ae359..487c4154 100644
--- a/sortix/Makefile
+++ b/sortix/Makefile
@@ -100,6 +100,8 @@ memorymanagement.o \
calltrace.o \
$(CPU)/calltrace.o \
kthread.o \
+interlock.o \
+$(CPU)/interlock.o \
panic.o \
keyboard.o \
kb/ps2.o \
diff --git a/sortix/include/sortix/kernel/interlock.h b/sortix/include/sortix/kernel/interlock.h
new file mode 100644
index 00000000..a4496231
--- /dev/null
+++ b/sortix/include/sortix/kernel/interlock.h
@@ -0,0 +1,48 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of Sortix.
+
+ Sortix is free software: you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ Sortix. If not, see .
+
+ interlock.cpp
+ Functions that perform non-atomic operations in an atomic manner.
+
+*******************************************************************************/
+
+#ifndef SORTIX_INTERLOCK_H
+#define SORTIX_INTERLOCK_H
+
+namespace Sortix {
+
+typedef unsigned long (*ilockfunc)(unsigned long, unsigned long);
+typedef struct
+{
+ unsigned long o; // old value
+ unsigned long n; // new value
+} ilret_t;
+
+// These atomicly modifies a value and return the previous value.
+ilret_t InterlockedModify(unsigned long* ptr,
+ ilockfunc f,
+ unsigned long user = 0);
+ilret_t InterlockedIncrement(unsigned long* ptr);
+ilret_t InterlockedDecrement(unsigned long* ptr);
+ilret_t InterlockedAdd(unsigned long* ptr, unsigned long arg);
+ilret_t InterlockedSub(unsigned long* ptr, unsigned long arg);
+
+} // namespace Sortix
+
+#endif
diff --git a/sortix/interlock.cpp b/sortix/interlock.cpp
new file mode 100644
index 00000000..e3a82242
--- /dev/null
+++ b/sortix/interlock.cpp
@@ -0,0 +1,73 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of Sortix.
+
+ Sortix is free software: you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ Sortix. If not, see .
+
+ interlock.cpp
+ Functions that perform non-atomic operations in an atomic manner.
+
+*******************************************************************************/
+
+#include
+#include
+
+namespace Sortix {
+
+// TODO: This is likely not the most optimal way to perform these operations.
+
+extern "C" ilret_t asm_interlocked_modify(unsigned long* val,
+ ilockfunc f,
+ unsigned long user);
+
+ilret_t InterlockedModify(unsigned long* ptr,
+ ilockfunc f,
+ unsigned long user)
+{
+ return asm_interlocked_modify(ptr, f, user);
+}
+
+static unsigned long AddFunction(unsigned long val, unsigned long arg)
+{
+ return val + arg;
+}
+
+static unsigned long SubFunction(unsigned long val, unsigned long arg)
+{
+ return val - arg;
+}
+
+ilret_t InterlockedIncrement(unsigned long* ptr)
+{
+ return InterlockedModify(ptr, AddFunction, 1);
+}
+
+ilret_t InterlockedDecrement(unsigned long* ptr)
+{
+ return InterlockedModify(ptr, SubFunction, 1);
+}
+
+ilret_t InterlockedAdd(unsigned long* ptr, unsigned long arg)
+{
+ return InterlockedModify(ptr, AddFunction, arg);
+}
+
+ilret_t InterlockedSub(unsigned long* ptr, unsigned long arg)
+{
+ return InterlockedModify(ptr, SubFunction, arg);
+}
+
+} // namespace Sortix
diff --git a/sortix/x64/interlock.s b/sortix/x64/interlock.s
new file mode 100644
index 00000000..d7430040
--- /dev/null
+++ b/sortix/x64/interlock.s
@@ -0,0 +1,56 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of Sortix.
+
+ Sortix is free software: you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ Sortix. If not, see .
+
+ x64/interlock.s
+ Functions that perform non-atomic operations in an atomic manner.
+
+*******************************************************************************/
+
+.section .text
+
+# Atomicly runs a function on a value and returns the unmodified value.
+# ilret_t
+# asm_interlocked_modify(unsigned long* val,
+# unsigned long (*func)(unsigned long, unsigned long),
+# unsigned long user);
+.global asm_interlocked_modify
+.type asm_interlocked_modify, @function
+asm_interlocked_modify:
+ pushq %rbp
+ movq %rsp, %rbp
+asm_interlocked_modify_retry:
+ # Save our parameters in case we need to retry.
+ pushq %rdi
+ pushq %rsi
+ pushq %rdx
+ # Read the current value and calculate the replacement.
+ movq (%rdi), %rdi
+ movq %rdx, %rsi
+ callq *%rsi
+ movq %rax, %rdx
+ popq %rax
+ popq %rdi
+ popq %rsi
+ # Atomicly assign the replacement if the value is unchanged.
+ cmpxchgq %rdx, (%rdi)
+ # Retry if the value was modified by someone else.
+ jnz asm_interlocked_modify_retry
+ # Return the old value in %rax, new one in %rdx.
+ leaveq
+ retq
diff --git a/sortix/x86/interlock.s b/sortix/x86/interlock.s
new file mode 100644
index 00000000..12f990b5
--- /dev/null
+++ b/sortix/x86/interlock.s
@@ -0,0 +1,61 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of Sortix.
+
+ Sortix is free software: you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ Sortix. If not, see .
+
+ x86/interlock.s
+ Functions that perform non-atomic operations in an atomic manner.
+
+*******************************************************************************/
+
+.section .text
+
+# Atomicly runs a function on a value and returns the unmodified value.
+# ilret_t
+# asm_interlocked_modify(unsigned long* val,
+# unsigned long (*func)(unsigned long, unsigned long),
+# unsigned long user);
+.global asm_interlocked_modify
+.type asm_interlocked_modify, @function
+asm_interlocked_modify:
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %ebx
+asm_interlocked_modify_retry:
+ # Read the current value and calculate the replacement.
+ movl 20(%ebp), %ecx # user
+ movl 16(%ebp), %edx # func
+ movl 12(%ebp), %ebx # val
+ movl (%ebx), %ebx # *val
+ pushl %ecx
+ pushl %ebx
+ call *%edx
+ # Atomicly assign the replacement if the value is unchanged.
+ movl %eax, %edx # New value in %edx
+ movl %ebx, %eax # Old value in %eax
+ movl 8(%ebp), %ebx # val
+ cmpxchgl %edx, (%ebx)
+ # Retry if the value was modified by someone else.
+ jnz asm_interlocked_modify_retry
+ # According to the calling convention, the first parameter is secretly a
+ # pointer to where we store the result, the old value first, then the new.
+ movl 8(%ebp), %ebx
+ movl %eax, 0(%ebx)
+ movl %edx, 4(%ebx)
+ popl %ebx
+ leavel
+ retl $0x4