From 37edd9dbc173fd4f4bd1fde407eccc6885b61611 Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Fri, 21 Feb 2020 15:05:48 +0100 Subject: [PATCH 01/42] tbb library --- .gitmodules | 3 +++ 3rdparty/install-tbb.sh | 22 ++++++++++++++++++++++ 3rdparty/tbb | 1 + 3 files changed, 26 insertions(+) create mode 100755 3rdparty/install-tbb.sh create mode 160000 3rdparty/tbb diff --git a/.gitmodules b/.gitmodules index e9ec8162..84805ac4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,3 +12,6 @@ path = 3rdparty/ihk url = https://github.com/ManyThreads/ihk.git ignore = dirty +[submodule "3rdparty/tbb"] + path = 3rdparty/tbb + url = git@github.com:ManyThreads/tbb.git diff --git a/3rdparty/install-tbb.sh b/3rdparty/install-tbb.sh new file mode 100755 index 00000000..0001ea8d --- /dev/null +++ b/3rdparty/install-tbb.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +TBBDIR="${SCRIPTDIR}/tbb" +CXXDIR="${SCRIPTDIR}/cxx-amd64" +TBB_BUILD_PREFIX="my_tbb" + +MYFLAGS=" -std=c++11 -march=native -Wfatal-errors -g" +MYFLAGS+=" -fno-stack-protector" +MYFLAGS+=" -nostdlib -nostdinc -nostdinc++" +MYFLAGS+=" -isystem ${CXXDIR}/usr/include/c++/v1" +MYFLAGS+=" -isystem ${CXXDIR}/usr/include" + +export CXXFLAGS="${MYFLAGS} ${CPLUS_FLAGS}" +export tbb_build_prefix="${TBB_BUILD_PREFIX}" + +echo $CPLUS_FLAGS + +cd $TBBDIR +make clean default +make extra_inc=big_iron.inc +cd - diff --git a/3rdparty/tbb b/3rdparty/tbb new file mode 160000 index 00000000..18070344 --- /dev/null +++ b/3rdparty/tbb @@ -0,0 +1 @@ +Subproject commit 18070344d755ece04d169e6cc40775cae9288cee From 6a04dd9c09d3b5d6320220b5d1907bfc43923524 Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Fri, 21 Feb 2020 15:06:22 +0100 Subject: [PATCH 02/42] tbb test --- 3rdparty/tbb | 2 +- kernel-amd64.config | 2 ++ kernel-ihk.config | 2 ++ kernel-knc.config | 2 ++ kernel/app/init-example/app/init.cc | 33 +++++++++++++++++++----- kernel/runtime/cxx/mcconf.module | 6 ++--- kernel/runtime/cxx/runtime/cxxsupport.cc | 13 ++++++---- kernel/runtime/cxx/runtime/pthread.cc | 6 +++++ 8 files changed, 51 insertions(+), 15 deletions(-) diff --git a/3rdparty/tbb b/3rdparty/tbb index 18070344..dda6d323 160000 --- a/3rdparty/tbb +++ b/3rdparty/tbb @@ -1 +1 @@ -Subproject commit 18070344d755ece04d169e6cc40775cae9288cee +Subproject commit dda6d323f817d05a96f95612d3b158c43cfca241 diff --git a/kernel-amd64.config b/kernel-amd64.config index 84e3083f..a4994b39 100644 --- a/kernel-amd64.config +++ b/kernel-amd64.config @@ -23,3 +23,5 @@ [config.vars] mythos_root = ".." cxx_path = "../3rdparty/cxx-amd64/usr" + tbb_build_path = "../3rdparty/tbb/build/my_tbb_release" + tbb_inc_path = "../3rdparty/tbb/include" diff --git a/kernel-ihk.config b/kernel-ihk.config index 0364e525..f7a53ff3 100644 --- a/kernel-ihk.config +++ b/kernel-ihk.config @@ -22,3 +22,5 @@ [config.vars] mythos_root = ".." cxx_path = "../3rdparty/cxx-amd64/usr" + tbb_build_path = "../3rdparty/tbb/build/my_tbb_release" + tbb_inc_path = "../3rdparty/tbb/include" diff --git a/kernel-knc.config b/kernel-knc.config index 1a7b2262..ec7b4cb3 100644 --- a/kernel-knc.config +++ b/kernel-knc.config @@ -26,3 +26,5 @@ [config.vars] mythos_root = ".." cxx_path = "../3rdparty/cxx-knc/usr" + tbb_build_path = "../3rdparty/tbb/build/my_tbb_release" + tbb_inc_path = "../3rdparty/tbb/include" diff --git a/kernel/app/init-example/app/init.cc b/kernel/app/init-example/app/init.cc index b2602826..99c61bf6 100644 --- a/kernel/app/init-example/app/init.cc +++ b/kernel/app/init-example/app/init.cc @@ -49,6 +49,8 @@ #include #include +#include "tbb/tbb.h" + mythos::InvocationBuf* msg_ptr asm("msg_ptr"); int main() asm("main"); @@ -242,7 +244,7 @@ void test_heap() { MLOG_INFO(mlog::app, "Test heap"); mythos::PortalLock pl(portal); uintptr_t vaddr = 22*1024*1024; // choose address different from invokation buffer - auto size = 4*1024*1024; // 2 MB + auto size = 64*1024*1024; // 2 MB auto align = 2*1024*1024; // 2 MB // allocate a 2MiB frame mythos::Frame f(capAlloc()); @@ -434,6 +436,24 @@ void test_InterruptControl() { MLOG_INFO(mlog::app, "test_InterruptControl end"); } +void test_TBB(){ + class say_hello + { + int id; + public: + say_hello(int i) : id(i) { } + void operator( ) ( ) const + { + printf("hello from task %d\n",id); + } + }; + + tbb::task_group tg; + for(int i=0; i<100; i++){ + tg.run(say_hello(i)); // spawn 1st task and return + } + tg.wait( ); // wait for tasks to complete +} int main() { @@ -441,18 +461,19 @@ int main() mythos::syscall_debug(str, sizeof(str)-1); MLOG_ERROR(mlog::app, "application is starting :)", DVARhex(msg_ptr), DVARhex(initstack_top)); - test_float(); + //test_float(); test_Example(); test_Portal(); - test_memory_root(); + //test_memory_root(); test_heap(); // heap must be initialized for tls test test_tls(); test_exceptions(); //test_InterruptControl(); //test_HostChannel(portal, 24*1024*1024, 2*1024*1024); - test_ExecutionContext(); - test_pthreads(); - test_omp(); + //test_ExecutionContext(); + //test_pthreads(); + //test_omp(); + test_TBB(); char const end[] = "bye, cruel world!"; mythos::syscall_debug(end, sizeof(end)-1); diff --git a/kernel/runtime/cxx/mcconf.module b/kernel/runtime/cxx/mcconf.module index d3137089..f0a2d93d 100644 --- a/kernel/runtime/cxx/mcconf.module +++ b/kernel/runtime/cxx/mcconf.module @@ -2,9 +2,9 @@ [module.cxxabi-app] incfiles = [ "runtime/futex.hh" ] appfiles = [ "runtime/cxxsupport.cc", "runtime/pthread.cc", "runtime/futex.cc" ] - provides = [ "vector", "queue", "functional", "pthread.h", "endian.h", "errno.h", "sys/mman.h", "sys/types.h", "stdlib.h", "sys/time.h", "stdatomic.h", "omp.h", "sys/resource.h", "bits/alltypes.h" ] + provides = [ "vector", "queue", "functional", "pthread.h", "endian.h", "errno.h", "sys/mman.h", "sys/types.h", "stdlib.h", "sys/time.h", "stdatomic.h", "omp.h", "sys/resource.h", "bits/alltypes.h", "tbb/tbb.h" ] makefile_head = ''' -APP_CPPFLAGS += -nostdinc -nostdinc++ -isystem ${vars.cxx_path}/include/c++/v1 -isystem ${vars.cxx_path}/include +APP_CPPFLAGS += -nostdinc -nostdinc++ -isystem ${vars.cxx_path}/include/c++/v1 -isystem ${vars.cxx_path}/include -I ${vars.tbb_inc_path} APP_LDFLAGS += -Wl,--eh-frame-hdr --sysroot=${vars.cxx_path}/../ -APP_LIBS += ${vars.cxx_path}/lib/libomp.a ${vars.cxx_path}/lib/libc++.a ${vars.cxx_path}/lib/libc++abi.a ${vars.cxx_path}/lib/libunwind.a ${vars.cxx_path}/lib/libc.a -lgcc +APP_LIBS += ${vars.cxx_path}/lib/libomp.a ${vars.tbb_build_path}/libtbb.a ${vars.cxx_path}/lib/libc++.a ${vars.cxx_path}/lib/libc++abi.a ${vars.cxx_path}/lib/libunwind.a ${vars.cxx_path}/lib/libc.a -lgcc ''' diff --git a/kernel/runtime/cxx/runtime/cxxsupport.cc b/kernel/runtime/cxx/runtime/cxxsupport.cc index 4c7f130d..5272100a 100644 --- a/kernel/runtime/cxx/runtime/cxxsupport.cc +++ b/kernel/runtime/cxx/runtime/cxxsupport.cc @@ -102,14 +102,14 @@ int prlimit( return 0; } -int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask) +int my_sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask) { //MLOG_DETAIL(mlog::app, "syscall sched_setaffinity", DVAR(pid), DVAR(cpusetsize), DVARhex(mask)); if(cpusetsize == NUM_CPUS && mask == NULL) return -EFAULT; return 0; } -int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask) +int my_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask) { //MLOG_DETAIL(mlog::app, "syscall sched_getaffinity", DVAR(pid), DVAR(cpusetsize), DVARhex(mask)); if (mask) { @@ -165,6 +165,9 @@ extern "C" long mythos_musl_syscall( case 24: // sched_yield //MLOG_ERROR(mlog::app, "syscall sched_yield NYI"); return 0; + case 25: // mremap + //MLOG_ERROR(mlog::app, "syscall sched_yield NYI"); + return 0; case 28: //madvise MLOG_WARN(mlog::app, "syscall madvise NYI"); return 0; @@ -193,9 +196,9 @@ extern "C" long mythos_musl_syscall( nullptr /*uaddr2*/, val2/*val2*/, a6/*val3*/); } case 203: // sched_setaffinity - return sched_setaffinity(a1, a2, reinterpret_cast(a3)); + return my_sched_setaffinity(a1, a2, reinterpret_cast(a3)); case 204: // sched_getaffinity - return sched_getaffinity(a1, a2, reinterpret_cast(a3)); + return my_sched_getaffinity(a1, a2, reinterpret_cast(a3)); case 228: // clock_gettime //MLOG_ERROR(mlog::app, "Error: mythos_musl_syscall clock_gettime", DVAR(num), //DVARhex(a1), DVARhex(a2), DVARhex(a3), @@ -264,7 +267,7 @@ int myclone( int (*func)(void *), void *stack, int flags, void *arg, int* ptid, void* tls, int* ctid) { - //MLOG_DETAIL(mlog::app, "myclone"); + MLOG_DETAIL(mlog::app, "myclone"); ASSERT(tls != nullptr); static int nextThread = 1; diff --git a/kernel/runtime/cxx/runtime/pthread.cc b/kernel/runtime/cxx/runtime/pthread.cc index dca229b5..1f55ef10 100644 --- a/kernel/runtime/cxx/runtime/pthread.cc +++ b/kernel/runtime/cxx/runtime/pthread.cc @@ -37,10 +37,12 @@ extern "C" int pthread_create(pthread_t *res, const pthread_attr_t *attrp, void } #endif +#ifdef use_pthreads_stubs extern "C" int pthread_detach(pthread_t){ MLOG_ERROR(mlog::app, __PRETTY_FUNCTION__); return 0; } +#endif #ifdef use_pthreads_stubs extern "C" _Noreturn void pthread_exit(void *){ @@ -627,15 +629,19 @@ extern "C" void _pthread_cleanup_pop(struct __ptcb *, int){ #ifdef _GNU_SOURCE +#ifdef use_pthreads_stubs extern "C" int pthread_getaffinity_np(pthread_t, size_t, struct cpu_set_t *){ MLOG_ERROR(mlog::app, __PRETTY_FUNCTION__); return 0; } +#endif +#ifdef use_pthreads_stubs extern "C" int pthread_setaffinity_np(pthread_t, size_t, const struct cpu_set_t *){ MLOG_ERROR(mlog::app, __PRETTY_FUNCTION__); return 0; } +#endif #ifdef use_pthreads_stubs extern "C" int pthread_getattr_np(pthread_t, pthread_attr_t *){ From 1f28333ac77552643aa34ff84d203b718790c54b Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Sat, 9 Jan 2021 19:30:23 +0100 Subject: [PATCH 03/42] fixes for TBB --- kernel/app/init-example/app/init.cc | 9 ++++++--- kernel/build/emu-quemu-amd64/mcconf.module | 4 ++-- kernel/runtime/cxx/runtime/cxxsupport.cc | 21 +++++++++++++-------- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/kernel/app/init-example/app/init.cc b/kernel/app/init-example/app/init.cc index 031a05d1..351f356c 100644 --- a/kernel/app/init-example/app/init.cc +++ b/kernel/app/init-example/app/init.cc @@ -205,7 +205,7 @@ void test_tls() void test_heap() { MLOG_INFO(mlog::app, "Test heap"); mythos::PortalLock pl(portal); - auto size = 4*1024*1024; // 2 MB + auto size = 64*1024*1024; // 2 MB auto align = 2*1024*1024; // 2 MB uintptr_t vaddr = mythos::round_up(uintptr_t(msg_ptr) + 1, align); // allocate a 2MiB frame @@ -386,6 +386,8 @@ void test_InterruptControl() { } void test_TBB(){ + MLOG_INFO(mlog::app, "Test TBB"); + class say_hello { int id; @@ -398,10 +400,11 @@ void test_TBB(){ }; tbb::task_group tg; - for(int i=0; i<100; i++){ + for(int i=0; i<10; i++){ tg.run(say_hello(i)); // spawn 1st task and return } tg.wait( ); // wait for tasks to complete + MLOG_INFO(mlog::app, "Test finished"); } bool primeTest(uint64_t n){ @@ -555,9 +558,9 @@ int main() test_pthreads(); //test_Rapl() test_processor_allocator(); + test_TBB(); test_process(); //test_CgaScreen(); - test_TBB(); char const end[] = "bye, cruel world!"; mythos::syscall_debug(end, sizeof(end)-1); diff --git a/kernel/build/emu-quemu-amd64/mcconf.module b/kernel/build/emu-quemu-amd64/mcconf.module index ecbfcdbd..ba67b0e1 100644 --- a/kernel/build/emu-quemu-amd64/mcconf.module +++ b/kernel/build/emu-quemu-amd64/mcconf.module @@ -5,7 +5,7 @@ provides = ["tag/emu-qemu"] makefile_head = ''' -QEMUFLAGS += -m 1024 -cpu SandyBridge -smp 4 +QEMUFLAGS += -m 1024 -cpu Skylake-Client-v1 -smp 4 # com1: text output to terminal QEMUFLAGS += -serial stdio # com2: object channel for remote procedure calls into mythos @@ -22,7 +22,7 @@ qemu: boot32.elf qemu-system-x86_64 $(QEMUFLAGS) -kernel boot32.elf qemu-text: boot32.elf - qemu-system-x86_64 -m 1024 -cpu SandyBridge -smp 4 -curses -kernel boot32.elf + qemu-system-x86_64 -m 1024 -cpu Skylake-Client-v1 -smp 4 -curses -kernel boot32.elf qemuidbg: boot32.elf qemu-system-x86_64 $(QEMUFLAGS) -kernel boot32.elf -qmp stdio diff --git a/kernel/runtime/cxx/runtime/cxxsupport.cc b/kernel/runtime/cxx/runtime/cxxsupport.cc index 40df94d6..6a04cbc6 100644 --- a/kernel/runtime/cxx/runtime/cxxsupport.cc +++ b/kernel/runtime/cxx/runtime/cxxsupport.cc @@ -60,6 +60,7 @@ extern mythos::Portal portal; extern mythos::CapMap myCS; extern mythos::PageMap myAS; extern mythos::KernelMemory kmem; +extern mythos::ProcessorAllocator pa; #ifndef NUM_CPUS #define NUM_CPUS (2) @@ -144,20 +145,24 @@ int prlimit( int my_sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask) { - //MLOG_DETAIL(mlog::app, "syscall sched_setaffinity", DVAR(pid), DVAR(cpusetsize), DVARhex(mask)); + MLOG_DETAIL(mlog::app, "syscall sched_setaffinity", DVAR(pid), DVAR(cpusetsize), DVARhex(mask)); if(cpusetsize == NUM_CPUS && mask == NULL) return -EFAULT; return 0; } int my_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask) { - //MLOG_DETAIL(mlog::app, "syscall sched_getaffinity", DVAR(pid), DVAR(cpusetsize), DVARhex(mask)); + MLOG_DETAIL(mlog::app, "syscall sched_getaffinity", DVAR(pid), DVAR(cpusetsize), DVARhex(mask)); if (mask) { //CPU_ZERO(mask); memset(mask, 0, cpusetsize); for(int i = 0; i < NUM_CPUS; i++) CPU_SET(i, mask); } - return NUM_CPUS; + if(cpusetsize > NUM_CPUS){ + return NUM_CPUS; + }else{ + return (-EINVAL); + } } void clock_gettime(long clk, struct timespec *ts){ @@ -213,7 +218,7 @@ extern "C" long mythos_musl_syscall( return 0; case 39: // getpid MLOG_WARN(mlog::app, "syscall getpid NYI"); - return 0; + return mythos_get_pthread_ec_self(); case 60: // exit(exit_code) //MLOG_ERROR(mlog::app, "syscall exit", DVAR(a1)); pthreadCleanerSemphore.exit(); @@ -287,10 +292,10 @@ extern "C" int munmap(void *start, size_t len) extern "C" int unmapself(void *start, size_t len) { - // dummy implementation - MLOG_ERROR(mlog::app, "unmapself: NYI!"); - ASSERT(0); - while(1); + // see pthread_exit: another pthread might reuse the memory before unmapped thread exited + MLOG_WARN(mlog::app, "unmapself: possible race condition! "); + MLOG_WARN(mlog::app, "unmapself: who's gonna free the EC and SC?! "); + mythos::heap.free(reinterpret_cast(start)); return 0; } From a46cacb50f5ec0c37ddd905e082a367d4b68ea07 Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Thu, 28 Jan 2021 17:05:37 +0100 Subject: [PATCH 04/42] worked on ThreadTeam --- kernel-amd64.config | 4 +- kernel/app/init-example/app/init.cc | 39 ++--- .../process_test/process_test/process_test.cc | 4 +- .../boot/init-loader-amd64/boot/load_init.cc | 9 +- .../boot/init-loader-amd64/boot/load_init.hh | 5 +- kernel/mythos/init/mythos/init.hh | 2 + .../mythos/protocol/ExecutionContext.hh | 7 +- .../invocation/mythos/protocol/common.hh | 1 + .../objects/ExecutionContext.hh | 1 + .../objects/processor-allocator/mcconf.module | 4 +- .../objects/ProcessorAllocator.cc | 113 +----------- .../objects/ProcessorAllocator.hh | 44 ++--- .../objects/SchedulingContext.cc | 9 +- .../objects/SchedulingContext.hh | 12 +- kernel/objects/thread-team/mcconf.module | 5 + .../thread-team/mythos/protocol/ThreadTeam.hh | 141 +++++++++++++++ .../thread-team/objects/PluginThreadTeam.cc | 32 ++++ .../thread-team/objects/PluginThreadTeam.hh | 103 +++++++++++ .../objects/thread-team/objects/ThreadTeam.cc | 164 ++++++++++++++++++ .../objects/thread-team/objects/ThreadTeam.hh | 153 ++++++++++++++++ kernel/runtime/cxx/runtime/cxxsupport.cc | 25 ++- kernel/runtime/kobject/mcconf.module | 2 +- kernel/runtime/kobject/runtime/ThreadTeam.hh | 67 +++++++ kernel/runtime/process/runtime/process.hh | 21 ++- 24 files changed, 765 insertions(+), 202 deletions(-) create mode 100644 kernel/objects/thread-team/mcconf.module create mode 100644 kernel/objects/thread-team/mythos/protocol/ThreadTeam.hh create mode 100644 kernel/objects/thread-team/objects/PluginThreadTeam.cc create mode 100644 kernel/objects/thread-team/objects/PluginThreadTeam.hh create mode 100644 kernel/objects/thread-team/objects/ThreadTeam.cc create mode 100644 kernel/objects/thread-team/objects/ThreadTeam.hh create mode 100644 kernel/runtime/kobject/runtime/ThreadTeam.hh diff --git a/kernel-amd64.config b/kernel-amd64.config index d311f6d9..9653123d 100644 --- a/kernel-amd64.config +++ b/kernel-amd64.config @@ -18,8 +18,8 @@ "plugin-dump-multiboot", "plugin-rapl-driver-intel", "app-init-example", - "test-synchronous-task", - "plugin-processor-allocator" + #"test-synchronous-task", + "objects-thread-team" ] [config.vars] diff --git a/kernel/app/init-example/app/init.cc b/kernel/app/init-example/app/init.cc index 763a77e9..51afccc0 100644 --- a/kernel/app/init-example/app/init.cc +++ b/kernel/app/init-example/app/init.cc @@ -35,7 +35,7 @@ #include "runtime/Example.hh" #include "runtime/PageMap.hh" #include "runtime/KernelMemory.hh" -#include "runtime/ProcessorAllocator.hh" +#include "runtime/ThreadTeam.hh" #include "runtime/CapAlloc.hh" #include "runtime/tls.hh" #include "runtime/mlog.hh" @@ -73,7 +73,7 @@ mythos::KernelMemory kmem(mythos::init::KM); mythos::KObject device_memory(mythos::init::DEVICE_MEM); cap_alloc_t capAlloc(myCS); mythos::RaplDriverIntel rapl(mythos::init::RAPL_DRIVER_INTEL); -mythos::ProcessorAllocator pa(mythos::init::PROCESSOR_ALLOCATOR); +mythos::ThreadTeam team(mythos::init::THREAD_TEAM); char threadstack[stacksize]; char* thread1stack_top = threadstack+stacksize/2; @@ -186,13 +186,13 @@ void test_tls() auto tls = mythos::setupNewTLS(); MLOG_INFO(mlog::app, "test_EC: create ec1 TLS", DVARhex(tls)); ASSERT(tls != nullptr); - auto sc = pa.alloc(pl).wait(); - TEST(sc); - auto res1 = ec1.create(kmem).as(myAS).cs(myCS).sched(sc->cap) + auto res1 = ec1.create(kmem).as(myAS).cs(myCS) .prepareStack(thread1stack_top).startFun(threadFun, nullptr) .suspended(false).fs(tls) .invokeVia(pl).wait(); TEST(res1); + auto res2 = team.tryRunEC(pl, ec1).wait(); + TEST(res2); TEST(ec1.setFSGS(pl,(uint64_t) tls, 0).wait()); mythos::syscall_signal(ec1.cap()); MLOG_INFO(mlog::app, "End test tls"); @@ -326,24 +326,24 @@ void test_ExecutionContext() auto tls1 = mythos::setupNewTLS(); ASSERT(tls1 != nullptr); - auto sc1 = pa.alloc(pl).wait(); - TEST(sc1); - auto res1 = ec1.create(kmem).as(myAS).cs(myCS).sched(sc1->cap) + auto res1 = ec1.create(kmem).as(myAS).cs(myCS) .prepareStack(thread1stack_top).startFun(&thread_main, nullptr) .suspended(false).fs(tls1) .invokeVia(pl).wait(); TEST(res1); + auto tres1 = team.tryRunEC(pl, ec1).wait(); + TEST(tres1); MLOG_INFO(mlog::app, "test_EC: create ec2"); auto tls2 = mythos::setupNewTLS(); ASSERT(tls2 != nullptr); - auto sc2 = pa.alloc(pl).wait(); - TEST(sc2); - auto res2 = ec2.create(kmem).as(myAS).cs(myCS).sched(sc2->cap) + auto res2 = ec2.create(kmem).as(myAS).cs(myCS)/*.sched(sc2->cap)*/ .prepareStack(thread2stack_top).startFun(&thread_main, nullptr) .suspended(false).fs(tls2) .invokeVia(pl).wait(); TEST(res2); + auto tres2 = team.tryRunEC(pl, ec2).wait(); + TEST(tres2); } for (volatile int i=0; i<100000; i++) { @@ -370,13 +370,13 @@ void test_InterruptControl() { mythos::ExecutionContext ec(capAlloc()); auto tls = mythos::setupNewTLS(); ASSERT(tls != nullptr); - auto sc = pa.alloc(pl).wait(); - TEST(sc); - auto res1 = ec.create(kmem).as(myAS).cs(myCS).sched(sc->cap) + auto res1 = ec.create(kmem).as(myAS).cs(myCS) .prepareStack(thread3stack_top).startFun(&thread_main, nullptr) .suspended(false).fs(tls) .invokeVia(pl).wait(); TEST(res1); + auto tres = team.tryRunEC(pl, ec).wait(); + TEST(tres); TEST(ic.registerForInterrupt(pl, ec.cap(), 0x32).wait()); TEST(ic.unregisterInterrupt(pl, 0x32).wait()); TEST(capAlloc.free(ec, pl)); @@ -495,16 +495,6 @@ void test_CgaScreen(){ MLOG_INFO(mlog::app, "Test CGA finished"); } -void test_processor_allocator(){ - MLOG_INFO(mlog::app, "Test processor allocator"); - mythos::PortalLock pl(portal); - auto sc = pa.alloc(pl).wait(); - TEST(sc); - auto res = pa.free(pl, sc->cap).wait(); - TEST(res); - MLOG_INFO(mlog::app, "Test processor allocator finished"); -} - void test_process(){ MLOG_INFO(mlog::app, "Test process"); @@ -533,7 +523,6 @@ int main() test_ExecutionContext(); test_pthreads(); //test_Rapl() - test_processor_allocator(); test_process(); //test_CgaScreen(); diff --git a/kernel/app/process_test/process_test/process_test.cc b/kernel/app/process_test/process_test/process_test.cc index 4077a36b..678310ce 100644 --- a/kernel/app/process_test/process_test/process_test.cc +++ b/kernel/app/process_test/process_test/process_test.cc @@ -33,8 +33,8 @@ #include "runtime/Example.hh" #include "runtime/PageMap.hh" #include "runtime/KernelMemory.hh" +#include "runtime/ThreadTeam.hh" #include "runtime/SimpleCapAlloc.hh" -#include "runtime/ProcessorAllocator.hh" #include "runtime/tls.hh" #include "runtime/mlog.hh" #include "runtime/InterruptControl.hh" @@ -59,7 +59,7 @@ mythos::KObject device_memory(mythos::init::DEVICE_MEM); mythos::SimpleCapAlloc< mythos::init::APP_CAP_START , mythos::init::SIZE-mythos::init::APP_CAP_START> capAlloc(myCS); mythos::RaplDriverIntel rapl(mythos::init::RAPL_DRIVER_INTEL); -mythos::ProcessorAllocator pa(mythos::init::PROCESSOR_ALLOCATOR); +mythos::ThreadTeam team(mythos::init::THREAD_TEAM); int main() diff --git a/kernel/boot/init-loader-amd64/boot/load_init.cc b/kernel/boot/init-loader-amd64/boot/load_init.cc index 508e659d..332ee52b 100644 --- a/kernel/boot/init-loader-amd64/boot/load_init.cc +++ b/kernel/boot/init-loader-amd64/boot/load_init.cc @@ -50,6 +50,7 @@ namespace mythos { Event event::initLoader; Event event::initLoaderEarly; +Event event::initEC; namespace boot { @@ -61,8 +62,7 @@ InitLoader::InitLoader(char* image) init::CAP_ALLOC_END-init::CAP_ALLOC_START) , memMapper(&capAlloc, mythos::init::KM) // default: no processor allocator present - , processorAllocatorPresent(false) - , initSC(init::SCHEDULERS_START) + , mapSchedulingContexts(true) { MLOG_INFO(mlog::boot, "found init application image at", (void*)image); } @@ -163,7 +163,7 @@ optional InitLoader::initCSpace() if (!res) RETHROW(res); } - if(!processorAllocatorPresent){ + if(mapSchedulingContexts){ ASSERT(cpu::getNumThreads() <= init::SCHEDULERS_START - init::APP_CAP_START); MLOG_INFO(mlog::boot, "... create scheduling context caps in caps", init::SCHEDULERS_START, "till", init::SCHEDULERS_START+cpu::getNumThreads()-1); @@ -288,11 +288,12 @@ optional InitLoader::createEC(uintptr_t ipc_vaddr) optional res(Error::SUCCESS); if (res) res = ec->setCapSpace(capAlloc.get(init::CSPACE)); if (res) res = ec->setAddressSpace(capAlloc.get(init::PML4)); - if (res) res = ec->setSchedulingContext(capAlloc.get(initSC)); + if (mapSchedulingContexts && res) res = ec->setSchedulingContext(capAlloc.get(init::SCHEDULERS_START)); if (!res) RETHROW(res); ec->getThreadState().rdi = ipc_vaddr; ec->setEntryPoint(_img.header()->entry); ec->setTrapped(false); + event::initEC.emit(*ec); RETURN(Error::SUCCESS); } diff --git a/kernel/boot/init-loader-amd64/boot/load_init.hh b/kernel/boot/init-loader-amd64/boot/load_init.hh index c6f09195..a6f7cb55 100644 --- a/kernel/boot/init-loader-amd64/boot/load_init.hh +++ b/kernel/boot/init-loader-amd64/boot/load_init.hh @@ -31,6 +31,7 @@ #include "util/VectorMax.hh" #include "objects/CapEntry.hh" #include "objects/IPageMap.hh" +#include "objects/ExecutionContext.hh" #include "util/events.hh" #include "boot/MemMapper.hh" #include "boot/CapAlloc.hh" @@ -80,8 +81,7 @@ namespace mythos { Portal* _portal; /* to be manipulated by optional processor allocator */ - bool processorAllocatorPresent; - CapPtr initSC; + bool mapSchedulingContexts; }; } // namespace boot @@ -89,6 +89,7 @@ namespace mythos { namespace event { extern Event initLoader; extern Event initLoaderEarly; + extern Event initEC; } } // namespace mythos diff --git a/kernel/mythos/init/mythos/init.hh b/kernel/mythos/init/mythos/init.hh index 4f4a5e1f..81c9616b 100644 --- a/kernel/mythos/init/mythos/init.hh +++ b/kernel/mythos/init/mythos/init.hh @@ -46,6 +46,7 @@ namespace init { CAPMAP_FACTORY, PAGEMAP_FACTORY, UNTYPED_MEMORY_FACTORY, + THREADTEAM_FACTORY, CAP_ALLOC_START, CAP_ALLOC_END = CAP_ALLOC_START+200, MSG_FRAME, @@ -54,6 +55,7 @@ namespace init { CPUDRIVER = SCHEDULERS_START+256, RAPL_DRIVER_INTEL, PROCESSOR_ALLOCATOR, + THREAD_TEAM, INTERRUPT_CONTROL_START, INTERRUPT_CONTROL_END = INTERRUPT_CONTROL_START+256, APP_CAP_START = 1024, diff --git a/kernel/mythos/invocation/mythos/protocol/ExecutionContext.hh b/kernel/mythos/invocation/mythos/protocol/ExecutionContext.hh index c8d21d44..0cd5e742 100644 --- a/kernel/mythos/invocation/mythos/protocol/ExecutionContext.hh +++ b/kernel/mythos/invocation/mythos/protocol/ExecutionContext.hh @@ -119,7 +119,12 @@ namespace mythos { struct Create : public KernelMemory::CreateBase { typedef InvocationBase response_type; Create(CapPtr dst, CapPtr factory) - : CreateBase(dst, factory, getLength(this), 3), start(false) { } + : CreateBase(dst, factory, getLength(this), 3), start(false) + { + as(null_cap); + cs(null_cap); + sched(null_cap); + } Amd64Registers regs; bool start; CapPtr as() const { return this->capPtrs[2]; } diff --git a/kernel/mythos/invocation/mythos/protocol/common.hh b/kernel/mythos/invocation/mythos/protocol/common.hh index 2214f382..d882c2e6 100644 --- a/kernel/mythos/invocation/mythos/protocol/common.hh +++ b/kernel/mythos/invocation/mythos/protocol/common.hh @@ -46,6 +46,7 @@ namespace mythos { CPUDRIVERKNC, RAPLDRIVERINTEL, PROCESSORALLOCATOR, + THREADTEAM, INTERRUPT_CONTROL, }; diff --git a/kernel/objects/execution-context/objects/ExecutionContext.hh b/kernel/objects/execution-context/objects/ExecutionContext.hh index d912da87..e9f7af80 100644 --- a/kernel/objects/execution-context/objects/ExecutionContext.hh +++ b/kernel/objects/execution-context/objects/ExecutionContext.hh @@ -117,6 +117,7 @@ namespace mythos { if (id == typeId()) return static_cast(this); if (id == typeId()) return static_cast(this); if (id == typeId()) return static_cast(this); + if (id == typeId()) return this; THROW(Error::TYPE_MISMATCH); } optional deleteCap(CapEntry&, Cap self, IDeleter& del) override; diff --git a/kernel/objects/processor-allocator/mcconf.module b/kernel/objects/processor-allocator/mcconf.module index 634a47fb..4f7b7c08 100644 --- a/kernel/objects/processor-allocator/mcconf.module +++ b/kernel/objects/processor-allocator/mcconf.module @@ -1,5 +1,5 @@ # -*- mode:toml; -*- [module.plugin-processor-allocator] - incfiles = [ "objects/PluginProcessorAllocator.hh", "objects/ProcessorAllocator.hh", "mythos/protocol/ProcessorAllocator.hh" ] - kernelfiles = [ "objects/ProcessorAllocator.cc", "objects/PluginProcessorAllocator.cc"] + incfiles = [ "objects/ProcessorAllocator.hh", "mythos/protocol/ProcessorAllocator.hh" ] + kernelfiles = [ "objects/ProcessorAllocator.cc"] diff --git a/kernel/objects/processor-allocator/objects/ProcessorAllocator.cc b/kernel/objects/processor-allocator/objects/ProcessorAllocator.cc index 7a7868d5..7eee27f2 100644 --- a/kernel/objects/processor-allocator/objects/ProcessorAllocator.cc +++ b/kernel/objects/processor-allocator/objects/ProcessorAllocator.cc @@ -21,7 +21,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * - * Copyright 2020 Philipp Gypser and contributors, BTU Cottbus-Senftenberg + * Copyright 2020 Philipp Gypser, BTU Cottbus-Senftenberg */ @@ -42,30 +42,6 @@ namespace mythos { MLOG_DETAIL(mlog::pm, __func__); } - void ProcessorAllocator::invoke(Tasklet* t, Cap self, IInvocation* msg) - { - MLOG_DETAIL(mlog::pm, __func__, DVAR(t), DVAR(msg)); - monitor.request(t, [=](Tasklet* t){ - Error err = Error::NOT_IMPLEMENTED; - switch (msg->getProtocol()) { - case protocol::ProcessorAllocator::proto: - err = protocol::ProcessorAllocator::dispatchRequest(this, msg->getMethod(), t, self, msg); - break; - } - if (err != Error::INHIBIT) { - msg->replyResponse(err); - monitor.requestDone(); - } - } ); - } - -/* IResult */ - void ProcessorAllocator::response(Tasklet* /*t*/, optional res){ - MLOG_DETAIL(mlog::pm, "revoke response:", res.state(), DVAR(toBeFreed)); - free(toBeFreed); - toBeFreed = 0; - } - /* ProcessorAllocator */ ProcessorAllocator::ProcessorAllocator() : sc(image2kernel(&mySC[0])) @@ -79,89 +55,8 @@ namespace mythos { } } - Error ProcessorAllocator::invokeAlloc(Tasklet*, Cap, IInvocation* msg){ - MLOG_DETAIL(mlog::pm, __func__); - auto id = alloc(); - - if(id){ - MLOG_DETAIL(mlog::pm, "allocated ", DVAR(*id)); - - auto data = msg->getMessage()->read(); - - optional dstEntry; - if(data.dstSpace() == null_cap){ // direct access - dstEntry = msg->lookupEntry(init::SCHEDULERS_START+*id, 32, true); // lookup for write access - if (!dstEntry){ - MLOG_WARN(mlog::pm, "Warning: cannot find dstEntry!"); - free(*id); - return dstEntry.state(); - } - - }else{ // indirect access - TypedCap dstSpace(msg->lookupEntry(data.dstSpace())); - if (!dstSpace){ - MLOG_WARN(mlog::pm, "Warning: cannot find dstSpace!"); - free(*id); - return dstSpace.state(); - } - - //auto dstEntryRef = dstSpace.lookup(data.dstPtr, data.dstDepth, true); // lookup for write - auto dstEntryRef = dstSpace.lookup(init::SCHEDULERS_START+*id, 32, true); // lookup for write - if (!dstEntryRef){ - MLOG_WARN(mlog::pm, "Warning: cannot find dstEntryRef!"); - free(*id); - return dstEntryRef.state(); - } - - dstEntry = dstEntryRef->entry; - } - - auto res = cap::reference(sc[*id], **dstEntry, sc[*id].cap()); - if(res){ - msg->getMessage()->write(init::SCHEDULERS_START+*id); - MLOG_DETAIL(mlog::pm, "map new sc ", DVAR(*id)); - }else{ - MLOG_WARN(mlog::pm, "Warning: cannot create SC entry!"); - free(*id); - msg->getMessage()->write(null_cap); - } - - }else{ - MLOG_WARN(mlog::pm, "allocation failed: no free cores available!"); - msg->getMessage()->write(null_cap); - } - return Error::SUCCESS; - } - - // todo: implement new revokation mechanism that suits this scenario - Error ProcessorAllocator::invokeFree(Tasklet* /*t*/, Cap, IInvocation* /*msg*/){ - MLOG_ERROR(mlog::pm, __func__, " NYI!"); - //auto data = msg->getMessage()->cast(); - //ASSERT(data->sc() >= init::SCHEDULERS_START); - //cpu::ThreadID id = data->sc() - init::SCHEDULERS_START; - //ASSERT(id < cpu::getNumThreads()); - //MLOG_ERROR(mlog::pm, "free SC", DVAR(data->sc()), DVAR(id)); - //toBeFreed = id; - //revokeOp._revoke(t, this, sc[id], this); - return Error::SUCCESS; - } - - void ProcessorAllocator::freeSC(Tasklet* t, cpu::ThreadID id){ - MLOG_DETAIL(mlog::pm, "freeSC", DVAR(id)); - monitor.request(t, [=](Tasklet* t){ - MLOG_DETAIL(mlog::pm, "monitor free", DVAR(id)); - toBeFreed = id; - revokeOp._revoke(t, this, sc[id], this); - } - ); - } - -/* LiFoProcessorAllocator */ - LiFoProcessorAllocator::LiFoProcessorAllocator() - : nFree(0) - {} - - optional LiFoProcessorAllocator::alloc(){ + optional ProcessorAllocator::alloc(){ + MLOG_WARN(mlog::pm, "alloc not synchronized yet"); optional ret; if(nFree > 0){ nFree--; @@ -170,7 +65,7 @@ namespace mythos { return ret; } - void LiFoProcessorAllocator::free(cpu::ThreadID id) { + void ProcessorAllocator::free(cpu::ThreadID id) { freeList[nFree] = id; nFree++; } diff --git a/kernel/objects/processor-allocator/objects/ProcessorAllocator.hh b/kernel/objects/processor-allocator/objects/ProcessorAllocator.hh index 4c733818..dccff36c 100644 --- a/kernel/objects/processor-allocator/objects/ProcessorAllocator.hh +++ b/kernel/objects/processor-allocator/objects/ProcessorAllocator.hh @@ -21,7 +21,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * - * Copyright 2020 Philipp Gypser and contributors, BTU Cottbus-Senftenberg + * Copyright 2020 Philipp Gypser, BTU Cottbus-Senftenberg */ #pragma once @@ -38,7 +38,6 @@ namespace mythos { class ProcessorAllocator : public IKernelObject - , public IResult { public: ProcessorAllocator(); @@ -46,42 +45,27 @@ class ProcessorAllocator /* IKernelObject */ optional deleteCap(CapEntry&, Cap self, IDeleter& del) override; void deleteObject(Tasklet* t, IResult* r) override; - void invoke(Tasklet* t, Cap self, IInvocation* msg) override; - - /* IResult */ - void response(Tasklet* /*t*/, optional res) override; + optional vcast(TypeId id) const override { + if (id == typeId()) return this; + THROW(Error::TYPE_MISMATCH); + } void init(); - Error invokeAlloc(Tasklet*, Cap, IInvocation* msg); - Error invokeFree(Tasklet* t, Cap, IInvocation* msg); - void freeSC(Tasklet* t, cpu::ThreadID id); - protected: - friend class PluginProcessorAllocator; - virtual optional alloc() = 0; - virtual void free(cpu::ThreadID id) = 0; - virtual unsigned numFree() = 0; + //todo: synchronize + optional alloc(); + void free(cpu::ThreadID id); + + CapEntry* getSC(cpu::ThreadID id){ + ASSERT(id < cpu::getNumThreads()); + return &sc[id]; + } - private: + protected: async::NestedMonitorDelegating monitor; - RevokeOperation revokeOp = {monitor}; - cpu::ThreadID toBeFreed = 0; CapEntry *sc; CapEntry mySC[MYTHOS_MAX_THREADS]; -}; - -class LiFoProcessorAllocator : public ProcessorAllocator -{ - public: - LiFoProcessorAllocator(); - - unsigned numFree() override { return nFree; } - optional alloc() override; - void free(cpu::ThreadID id) override; - - private: unsigned nFree; cpu::ThreadID freeList[MYTHOS_MAX_THREADS]; }; - } // namespace mythos diff --git a/kernel/objects/scheduling-context/objects/SchedulingContext.cc b/kernel/objects/scheduling-context/objects/SchedulingContext.cc index 456dcbdc..1d712bfc 100644 --- a/kernel/objects/scheduling-context/objects/SchedulingContext.cc +++ b/kernel/objects/scheduling-context/objects/SchedulingContext.cc @@ -47,8 +47,13 @@ namespace mythos { readyQueue.remove(ec); current_handle.store(nullptr); if(readyQueue.empty()){ - MLOG_DETAIL(mlog::sched, "call idleSC"); - event::idleSC.emit(&paTask, home->getThreadID()); + MLOG_INFO(mlog::sched, "call idleSC"); + if(myTeam.load() != nullptr){ + myTeam.load()->notifyIdle(&paTask, home->getThreadID()); + }else{ + MLOG_WARN(mlog::sched, "No ThreadTeam registered!"); + } + }else{ MLOG_INFO(mlog::sched, "ready queue not empty!"); } diff --git a/kernel/objects/scheduling-context/objects/SchedulingContext.hh b/kernel/objects/scheduling-context/objects/SchedulingContext.hh index 1f82f78e..6fe3f74b 100644 --- a/kernel/objects/scheduling-context/objects/SchedulingContext.hh +++ b/kernel/objects/scheduling-context/objects/SchedulingContext.hh @@ -32,6 +32,7 @@ #include #include "util/error-trace.hh" #include "util/events.hh" +#include "objects/ThreadTeam.hh" namespace mythos { @@ -73,7 +74,9 @@ namespace mythos { , public IScheduler { public: - SchedulingContext() { } + SchedulingContext() + : myTeam(nullptr) + { } void init(async::Place* home) { this->home = home; } virtual ~SchedulingContext() {} @@ -87,10 +90,16 @@ namespace mythos { void unbind(handle_t* ec_handle) override; void ready(handle_t* ec_handle) override; + public: //ThreadTeam + void registerThreadTeam(ThreadTeam* tt){ + myTeam.store(tt); + }; + public: // IKernelObject interface optional deleteCap(CapEntry&, Cap, IDeleter&) override { RETURN(Error::SUCCESS); } optional vcast(TypeId id) const override { if (id == typeId()) return static_cast(this); + if (id == typeId()) return this; THROW(Error::TYPE_MISMATCH); } @@ -100,6 +109,7 @@ namespace mythos { std::atomic current_handle = {nullptr}; //< the currently selected execution context Tasklet paTask; //task for communication with processor allocator + std::atomic myTeam; }; namespace event { diff --git a/kernel/objects/thread-team/mcconf.module b/kernel/objects/thread-team/mcconf.module new file mode 100644 index 00000000..7ce1e27c --- /dev/null +++ b/kernel/objects/thread-team/mcconf.module @@ -0,0 +1,5 @@ +# -*- mode:toml; -*- +[module.objects-thread-team] + incfiles = [ "objects/ThreadTeam.hh", "mythos/protocol/ThreadTeam.hh", "objects/PluginThreadTeam.hh" ] + kernelfiles = [ "objects/ThreadTeam.cc", "objects/PluginThreadTeam.cc"] + diff --git a/kernel/objects/thread-team/mythos/protocol/ThreadTeam.hh b/kernel/objects/thread-team/mythos/protocol/ThreadTeam.hh new file mode 100644 index 00000000..0dcc809b --- /dev/null +++ b/kernel/objects/thread-team/mythos/protocol/ThreadTeam.hh @@ -0,0 +1,141 @@ +/* -*- mode:C++; indent-tabs-mode:nil; -*- */ +/* MIT License -- MyThOS: The Many-Threads Operating System + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Copyright 2021 Philipp Gypser, BTU Cottbus-Senftenberg + */ +#pragma once + +#include "mythos/protocol/common.hh" +#include "mythos/protocol/KernelMemory.hh" +#include "util/align.hh" + + +namespace mythos { + namespace protocol { + + struct ThreadTeam { + constexpr static uint8_t proto = THREADTEAM; + + enum Methods : uint8_t { + TRYRUNEC, + RETTRYRUNEC, + DEMANDRUNEC, + RETDEMANDRUNEC, + FORCERUNEC, + RETFORCERUNEC, + RUNNEXTTOEC, + RETRUNNEXTTOEC + }; + + struct Create : public KernelMemory::CreateBase { + typedef InvocationBase response_type; + //constexpr static uint16_t label = (proto<<8) + CREATE; + Create(CapPtr dst, CapPtr factory, CapPtr pa) + : CreateBase(dst, factory, getLength(this), 0) + { + this->capPtrs[2] = pa; + } + CapPtr pa() const { return this->capPtrs[2]; } + }; + + struct TryRunEC : public InvocationBase { + constexpr static uint16_t label = (proto<<8) + TRYRUNEC; + TryRunEC(CapPtr ec) : InvocationBase(label,getLength(this)) { + addExtraCap(ec); + } + + // execution context to be scheduled + CapPtr ec() const { return this->capPtrs[0]; } + }; + + struct RetTryRunEC : public InvocationBase { + constexpr static uint16_t label = (proto<<8) + RETTRYRUNEC; + RetTryRunEC() : InvocationBase(label,getLength(this)) { + } + }; + + struct DemandRunEC : public InvocationBase { + constexpr static uint16_t label = (proto<<8) + DEMANDRUNEC; + DemandRunEC(CapPtr ec) : InvocationBase(label,getLength(this)) { + addExtraCap(ec); + } + + // execution context to be scheduled + CapPtr ec() const { return this->capPtrs[0]; } + }; + + struct RetDemandRunEC : public InvocationBase { + constexpr static uint16_t label = (proto<<8) + RETDEMANDRUNEC; + RetDemandRunEC() : InvocationBase(label,getLength(this)) { + } + }; + + struct ForceRunEC : public InvocationBase { + constexpr static uint16_t label = (proto<<8) + FORCERUNEC; + ForceRunEC(CapPtr ec) : InvocationBase(label,getLength(this)) { + addExtraCap(ec); + } + + // execution context to be scheduled + CapPtr ec() const { return this->capPtrs[0]; } + }; + + struct RetForceRunEC : public InvocationBase { + constexpr static uint16_t label = (proto<<8) + RETFORCERUNEC; + RetForceRunEC() : InvocationBase(label,getLength(this)) { + } + }; + + struct RunNextToEC : public InvocationBase { + constexpr static uint16_t label = (proto<<8) + RUNNEXTTOEC; + RunNextToEC(CapPtr ec, CapPtr ec_place) : InvocationBase(label,getLength(this)) { + addExtraCap(ec); + addExtraCap(ec_place); + } + + // execution context to be scheduled + CapPtr ec() const { return this->capPtrs[0]; } + CapPtr ec_place() const { return this->capPtrs[1]; } + }; + + struct RetRunNextToEC : public InvocationBase { + constexpr static uint16_t label = (proto<<8) + RETRUNNEXTTOEC; + RetRunNextToEC() : InvocationBase(label,getLength(this)) { + } + }; + + template + static Error dispatchRequest(IMPL* obj, uint8_t m, ARGS const&...args) { + switch(Methods(m)) { + case TRYRUNEC: return obj->invokeTryRunEC(args...); + case DEMANDRUNEC: return obj->invokeDemandRunEC(args...); + case FORCERUNEC: return obj->invokeForceRunEC(args...); + case RUNNEXTTOEC: return obj->invokeRunNextToEC(args...); + default: return Error::NOT_IMPLEMENTED; + } + } + + }; + + }// namespace protocol +}// namespace mythos diff --git a/kernel/objects/thread-team/objects/PluginThreadTeam.cc b/kernel/objects/thread-team/objects/PluginThreadTeam.cc new file mode 100644 index 00000000..bb39cf43 --- /dev/null +++ b/kernel/objects/thread-team/objects/PluginThreadTeam.cc @@ -0,0 +1,32 @@ +/* -*- mode:C++; indent-tabs-mode:nil; -*- */ +/* MIT License -- MyThOS: The Many-Threads Operating System + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Copyright 2021 Philipp Gypser, BTU Cottbus-Senftenberg + */ + +#include "objects/PluginThreadTeam.hh" + + +mythos::PluginThreadTeam pluginThreadTeam; +mythos::PluginThreadTeamActivator pluginThreadTeamActivator; + diff --git a/kernel/objects/thread-team/objects/PluginThreadTeam.hh b/kernel/objects/thread-team/objects/PluginThreadTeam.hh new file mode 100644 index 00000000..b89acf21 --- /dev/null +++ b/kernel/objects/thread-team/objects/PluginThreadTeam.hh @@ -0,0 +1,103 @@ +/* -*- mode:C++; indent-tabs-mode:nil; -*- */ +/* MIT License -- MyThOS: The Many-Threads Operating System + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Copyright 2021 Philipp Gypser, BTU Cottbus-Senftenberg + */ +#pragma once + +#include "objects/ThreadTeam.hh" +#include "util/events.hh" +#include "boot/load_init.hh" +#include "mythos/init.hh" +#include "boot/mlog.hh" +#include "util/assert.hh" + +namespace mythos { + +namespace factory { + ThreadTeamFactory threadTeam; +} + + class PluginThreadTeamActivator + : public EventHook + { + public: + PluginThreadTeamActivator() { + event::initLoaderEarly.add(this); + } + virtual ~PluginThreadTeamActivator() {} + + void processEvent(boot::InitLoader& loader) override { + MLOG_ERROR(mlog::pm, "prevent mapping of all scheduling contexts into CSpace"); + loader.mapSchedulingContexts = false; + } + + }; + + class PluginThreadTeam + : public EventHook + , public EventHook + { + public: + PluginThreadTeam() + : tt(nullptr) + { + event::initLoader.add(this); + event::initEC.add(this); + } + virtual ~PluginThreadTeam() {} + + void processEvent(boot::InitLoader& loader) override { + MLOG_DETAIL(mlog::pm, "init processor allocator"); + pa.init(); + MLOG_DETAIL(mlog::pm, "map processor allocator"); + OOPS(loader.csSet(init::PROCESSOR_ALLOCATOR, pa)); + MLOG_DETAIL(mlog::pm, "map thread team factory"); + OOPS(loader.csSet(init::THREADTEAM_FACTORY, factory::threadTeam)); + MLOG_DETAIL(mlog::pm, "get processor allocator"); + auto pae = loader.capAlloc.get(init::PROCESSOR_ALLOCATOR); + ASSERT(pae); + MLOG_DETAIL(mlog::pm, "create initial thread team"); + auto obj = loader.create(loader.capAlloc.get(init::THREAD_TEAM), *pae ); + if(obj){ + MLOG_DETAIL(mlog::pm, "thread team created successfully"); + tt = *obj; + }else{ + MLOG_ERROR(mlog::pm, "ERROR: thread team creation failed!"); + } + } + + void processEvent(ExecutionContext* ec) override { + MLOG_DETAIL(mlog::pm, "runEc"); + ASSERT(tt != nullptr); + tt->tryRunEC(ec); + } + + ThreadTeam* tt; + ProcessorAllocator pa; + }; + +extern mythos::PluginThreadTeam pluginThreadTeam; +extern mythos::PluginThreadTeamActivator pluginThreadTeamActivator; +} // namespace mythos + diff --git a/kernel/objects/thread-team/objects/ThreadTeam.cc b/kernel/objects/thread-team/objects/ThreadTeam.cc new file mode 100644 index 00000000..314a63d8 --- /dev/null +++ b/kernel/objects/thread-team/objects/ThreadTeam.cc @@ -0,0 +1,164 @@ +/* -*- mode:C++; indent-tabs-mode:nil; -*- */ +/* MIT License -- MyThOS: The Many-Threads Operating System + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Copyright 2021 Philipp Gypser, BTU Cottbus-Senftenberg + */ + + +#include "objects/ThreadTeam.hh" +#include "objects/mlog.hh" + +namespace mythos { + +/* IKernelObject */ + optional ThreadTeam::deleteCap(CapEntry&, Cap, IDeleter&) + { + MLOG_DETAIL(mlog::pm, __func__); + RETURN(Error::SUCCESS); + } + + void ThreadTeam::deleteObject(Tasklet*, IResult*) + { + MLOG_DETAIL(mlog::pm, __func__); + } + + void ThreadTeam::invoke(Tasklet* t, Cap self, IInvocation* msg) + { + MLOG_DETAIL(mlog::pm, __func__, DVAR(t), DVAR(msg)); + monitor.request(t, [=](Tasklet* t){ + Error err = Error::NOT_IMPLEMENTED; + switch (msg->getProtocol()) { + case protocol::ThreadTeam::proto: + err = protocol::ThreadTeam::dispatchRequest(this, msg->getMethod(), t, self, msg); + break; + } + if (err != Error::INHIBIT) { + msg->replyResponse(err); + monitor.requestDone(); + } + } ); + } + +/* IResult */ + void ThreadTeam::response(Tasklet* /*t*/, optional res){ + MLOG_DETAIL(mlog::pm, "revoke response:", res.state()); + } + +/* ThreadTeam */ + ThreadTeam::ThreadTeam(IAsyncFree* memory) + : memory(memory) + , nFree(0) + , nUsed(0) + {} + + void ThreadTeam::tryRunEC(ExecutionContext* ec){ + MLOG_DETAIL(mlog::pm, __func__); + auto pal = pa.get(); + ASSERT(pal); + + auto id = popFree(); + if(id){ + MLOG_DETAIL(mlog::pm, "take SC from Team ", DVAR(*id)); + }else{ + MLOG_DETAIL(mlog::pm, "try alloc SC from PA"); + id = pal->alloc(); + } + if(id){ + auto sce = pal->getSC(*id); + TypedCap sc(sce->cap()); + sc->registerThreadTeam(this); + pushUsed(*id); + auto ret = ec->setSchedulingContext(sce); + MLOG_DETAIL(mlog::pm, "Init EC bind SC", DVAR(*id)); + }else{ + MLOG_ERROR(mlog::pm, "Cannot allocate SC for init EC"); + } + } + + Error ThreadTeam::invokeTryRunEC(Tasklet* t, Cap, IInvocation* msg){ + MLOG_ERROR(mlog::pm, __func__); + + auto data = msg->getMessage()->read(); + auto ece = msg->lookupEntry(data.ec()); + if(!ece){ + MLOG_ERROR(mlog::pm, "Error: Did not find EC!"); + return Error::INVALID_CAPABILITY; + } + + TypedCap ec(ece); + + auto pal = pa.get(); + ASSERT(pal); + auto id = popFree(); + if(id){ + MLOG_DETAIL(mlog::pm, "take SC from Team ", DVAR(*id)); + }else{ + MLOG_DETAIL(mlog::pm, "try alloc SC from PA"); + id = pal->alloc(); + } + if(id){ + MLOG_DETAIL(mlog::pm, "allocated thread id ", DVAR(*id)); + auto sce = pal->getSC(*id); + TypedCap sc(sce->cap()); + sc->registerThreadTeam(this); + pushUsed(*id); + auto ret = ec->setSchedulingContext(sce); + return ret.state(); + } + return Error::INSUFFICIENT_RESOURCES; + } + + Error ThreadTeam::invokeDemandRunEC(Tasklet* t, Cap, IInvocation* msg){ + MLOG_ERROR(mlog::pm, __func__, " NYI!"); + return Error::NOT_IMPLEMENTED; + } + + Error ThreadTeam::invokeForceRunEC(Tasklet* t, Cap, IInvocation* msg){ + MLOG_ERROR(mlog::pm, __func__, " NYI!"); + return Error::NOT_IMPLEMENTED; + } + + Error ThreadTeam::invokeRunNextToEC(Tasklet* t, Cap, IInvocation* msg){ + MLOG_ERROR(mlog::pm, __func__, " NYI!"); + return Error::NOT_IMPLEMENTED; + } + + optional + ThreadTeamFactory::factory(CapEntry* dstEntry, CapEntry* memEntry, Cap memCap, IAllocator* mem, CapEntry* pae){ + auto obj = mem->create(); + if (!obj) { + dstEntry->reset(); + RETHROW(obj); + } + TypedCap pa(pae); + if (!pa) RETHROW(pa); + obj->pa.set(*obj, pae, pa.cap()); + Cap cap(*obj); + auto res = cap::inherit(*memEntry, memCap, *dstEntry, cap); + if (!res) { + mem->free(*obj); // mem->release(obj) goes throug IKernelObject deletion mechanism + RETHROW(res); + } + return *obj; + } +} // namespace mythos diff --git a/kernel/objects/thread-team/objects/ThreadTeam.hh b/kernel/objects/thread-team/objects/ThreadTeam.hh new file mode 100644 index 00000000..048cfd2b --- /dev/null +++ b/kernel/objects/thread-team/objects/ThreadTeam.hh @@ -0,0 +1,153 @@ +/* -*- mode:C++; indent-tabs-mode:nil; -*- */ +/* MIT License -- MyThOS: The Many-Threads Operating System + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Copyright 2021 Philipp Gypser, BTU Cottbus-Senftenberg + */ +#pragma once + +#include "async/NestedMonitorDelegating.hh" +#include "objects/IFactory.hh" +#include "objects/IKernelObject.hh" +#include "cpu/hwthreadid.hh" +#include "mythos/protocol/ThreadTeam.hh" +#include "boot/mlog.hh" +#include "objects/RevokeOperation.hh" +#include "objects/ProcessorAllocator.hh" +#include "objects/ExecutionContext.hh" +#include "async/IResult.hh" + +namespace mythos { + + class ThreadTeam + : public IKernelObject + , public IResult + { + public: + ThreadTeam(IAsyncFree* memory); + + /* IKernelObject */ + optional deleteCap(CapEntry&, Cap self, IDeleter& del) override; + void deleteObject(Tasklet* t, IResult* r) override; + void invoke(Tasklet* t, Cap self, IInvocation* msg) override; + optional vcast(TypeId id) const override { + if (id == typeId()) return this; + THROW(Error::TYPE_MISMATCH); + } + + /* IResult */ + void response(Tasklet* /*t*/, optional res) override; + + void tryRunEC(ExecutionContext* ec); + Error invokeTryRunEC(Tasklet* t, Cap, IInvocation* msg); + Error invokeDemandRunEC(Tasklet* t, Cap, IInvocation* msg); + Error invokeForceRunEC(Tasklet* t, Cap, IInvocation* msg); + Error invokeRunNextToEC(Tasklet* t, Cap, IInvocation* msg); + + void bind(optional ) { + MLOG_DETAIL(mlog::pm, "bind processor allocator"); + } + + void unbind(optional ) { + MLOG_ERROR(mlog::pm, "ERROR: unbind processor allocator"); + } + + void notifyIdle(Tasklet* t, cpu::ThreadID id){ + MLOG_DETAIL(mlog::pm, __func__, DVAR(id)); + monitor.request(t, [=](Tasklet* t){ + removeUsed(id); + pushFree(id); + monitor.responseAndRequestDone(); + }); + } + private: + void pushFree(cpu::ThreadID id){ + MLOG_DETAIL(mlog::pm, __func__, DVAR(id)); + freeList[nFree] = id; + nFree++; + } + + optional popFree(){ + MLOG_DETAIL(mlog::pm, __func__); + optional ret; + if(nFree > 0){ + nFree--; + ret = freeList[nFree]; + } + return ret; + } + + void pushUsed(cpu::ThreadID id){ + MLOG_DETAIL(mlog::pm, __func__, DVAR(id)); + usedList[nUsed] = id; + nUsed++; + } + + void removeUsed(cpu::ThreadID id){ + MLOG_DETAIL(mlog::pm, __func__, DVAR(id)); + for(unsigned i = 0; i < nUsed; i++){ + if(usedList[i] == id){ + nUsed--; + for(; i < nUsed; i++){ + usedList[i] = usedList[i+1]; + } + return; + } + } + MLOG_ERROR(mlog::pm, "ERROR: did not find used ThreadID ", id); + } + + + async::NestedMonitorDelegating monitor; + + friend class ThreadTeamFactory; + CapRef pa; + cpu::ThreadID freeList[MYTHOS_MAX_THREADS]; + unsigned nFree; + cpu::ThreadID usedList[MYTHOS_MAX_THREADS]; + unsigned nUsed; + + IAsyncFree* memory; + }; + + class ThreadTeamFactory : public FactoryBase + { + public: + typedef protocol::ThreadTeam::Create message_type; + + static optional + factory(CapEntry* dstEntry, CapEntry* memEntry, Cap memCap, IAllocator* mem, CapEntry* pae); + + Error factory(CapEntry* dstEntry, CapEntry* memEntry, Cap memCap, + IAllocator* mem, IInvocation* msg) const override { + MLOG_DETAIL(mlog::pm, __PRETTY_FUNCTION__); + auto data = msg->getMessage()->read(); + auto paEntry = msg->lookupEntry(data.pa()); + if (!paEntry){ + MLOG_ERROR(mlog::pm, "ERROR: cannot find processor allocator entry reference!"); + return Error::INVALID_CAPABILITY; + } + return factory(dstEntry, memEntry, memCap, mem, *paEntry).state(); + } + }; + +} // namespace mythos diff --git a/kernel/runtime/cxx/runtime/cxxsupport.cc b/kernel/runtime/cxx/runtime/cxxsupport.cc index 83eac48f..bf5af85c 100644 --- a/kernel/runtime/cxx/runtime/cxxsupport.cc +++ b/kernel/runtime/cxx/runtime/cxxsupport.cc @@ -48,19 +48,19 @@ #include "runtime/Example.hh" #include "runtime/PageMap.hh" #include "runtime/KernelMemory.hh" -#include "runtime/ProcessorAllocator.hh" #include "runtime/CapAlloc.hh" #include "runtime/tls.hh" #include "runtime/futex.hh" #include "runtime/umem.hh" #include "runtime/thread-extra.hh" +#include "runtime/ThreadTeam.hh" extern mythos::InvocationBuf* msg_ptr asm("msg_ptr"); extern mythos::Portal portal; extern mythos::CapMap myCS; extern mythos::PageMap myAS; extern mythos::KernelMemory kmem; -extern mythos::ProcessorAllocator pa; +extern mythos::ThreadTeam team; #ifndef NUM_CPUS #define NUM_CPUS (2) @@ -326,26 +326,23 @@ int myclone( if (ptid && (flags&CLONE_PARENT_SETTID)) *ptid = int(ec.cap()); // @todo store thread-specific ctid pointer, which should set to 0 by the OS on the thread's exit - auto sc = pa.alloc(pl).wait(); - ASSERT(sc); - if(sc->cap == mythos::null_cap){ - MLOG_WARN(mlog::app, "Processor allocation failed!"); - //todo: set errno = EAGAIN - return (-1); - } - - auto res1 = ec.create(kmem) + auto res = ec.create(kmem) .as(myAS) .cs(myCS) - .sched(sc->cap) + //.sched(sc->cap) .rawStack(rsp) .rawFun(func, arg) .suspended(false) .fs(tls) .invokeVia(pl) .wait(); - //MLOG_DETAIL(mlog::app, DVAR(ec.cap())); - return ec.cap(); + auto tres = team.tryRunEC(pl, ec).wait(); + if(tres){ + return ec.cap(); + } + MLOG_WARN(mlog::app, "Processor allocation failed!"); + //todo: set errno = EAGAIN + return (-1); } extern "C" int clone(int (*func)(void *), void *stack, int flags, void *arg, ...) diff --git a/kernel/runtime/kobject/mcconf.module b/kernel/runtime/kobject/mcconf.module index 77712dbd..4e7b0589 100644 --- a/kernel/runtime/kobject/mcconf.module +++ b/kernel/runtime/kobject/mcconf.module @@ -11,5 +11,5 @@ incfiles = [ "runtime/CapAlloc.hh", "runtime/InterruptControl.hh", "runtime/RaplDriverIntel.hh", - "runtime/ProcessorAllocator.hh" + "runtime/ThreadTeam.hh" ] diff --git a/kernel/runtime/kobject/runtime/ThreadTeam.hh b/kernel/runtime/kobject/runtime/ThreadTeam.hh new file mode 100644 index 00000000..6080b9af --- /dev/null +++ b/kernel/runtime/kobject/runtime/ThreadTeam.hh @@ -0,0 +1,67 @@ +/* -*- mode:C++; indent-tabs-mode:nil; -*- */ +/* MIT License -- MyThOS: The Many-Threads Operating System + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Copyright 2021 Philipp Gypser, BTU Cottbus-Senftenberg + */ +#pragma once + +#include "runtime/PortalBase.hh" +#include "mythos/protocol/ThreadTeam.hh" +#include "runtime/ExecutionContext.hh" +#include "mythos/init.hh" + +namespace mythos { + + class ThreadTeam : public KObject + { + public: + + ThreadTeam() {} + ThreadTeam(CapPtr cap) : KObject(cap) {} + + PortalFuture create(PortalLock pr, KernelMemory kmem, CapPtr pa, CapPtr factory = init::THREADTEAM_FACTORY){ + return pr.invoke(kmem.cap(), _cap, factory, pa); + } + + PortalFuture tryRunEC(PortalLock pr, ExecutionContext ec){ + return pr.invoke(_cap, ec.cap()); + } + + PortalFuture runNextToEC(PortalLock pr, ExecutionContext ec, ExecutionContext ec_place){ + return pr.invoke(_cap, ec.cap(), ec_place.cap()); + } + + PortalFuture demandRunEC(PortalLock pr, ExecutionContext ec){ + return pr.invoke(_cap, ec.cap()); + } + + PortalFuture revokeDemand(PortalLock pr, ExecutionContext ec){ + return pr.invoke(_cap, ec.cap()); + } + + PortalFuture forceRunEC(PortalLock pr, ExecutionContext ec){ + return pr.invoke(_cap, ec.cap()); + } + }; + +} // namespace mythos diff --git a/kernel/runtime/process/runtime/process.hh b/kernel/runtime/process/runtime/process.hh index 3299a374..efc6bfc0 100644 --- a/kernel/runtime/process/runtime/process.hh +++ b/kernel/runtime/process/runtime/process.hh @@ -8,11 +8,12 @@ #include "util/elf64.hh" #include "util/align.hh" #include "runtime/CapAlloc.hh" +#include "runtime/ThreadTeam.hh" extern mythos::CapMap myCS; extern mythos::PageMap myAS; extern mythos::KernelMemory kmem; -extern mythos::ProcessorAllocator pa; +extern mythos::ThreadTeam team; using namespace mythos; @@ -242,18 +243,24 @@ class Process{ /* create EC */ MLOG_DETAIL(mlog::app, "create EC ...", DVARhex(img.header()->entry)); - auto sc = pa.alloc(pl).wait(); - TEST(sc); - MLOG_DETAIL(mlog::app, "allocated SC", DVAR(sc->cap)); ExecutionContext ec(capAlloc()); - res = ec.create(kmem).as(pm4).cs(cs).sched(sc->cap) + res = ec.create(kmem).as(pm4).cs(cs) .rawFun(reinterpret_cast(img.header()->entry), reinterpret_cast(*ipc_vaddr)) .suspended(true) .invokeVia(pl).wait(); TEST(res); - MLOG_DETAIL(mlog::app, "move SC"); - res = myCS.move(pl, sc->cap, max_cap_depth, cs.cap(), sc->cap, max_cap_depth).wait(); + + /* create ThreadTeam */ + MLOG_DETAIL(mlog::app, "create ThreadTeam ..."); + ThreadTeam tt(capAlloc()); + res = tt.create(pl, kmem, init::PROCESSOR_ALLOCATOR).wait(); + TEST(res); + MLOG_DETAIL(mlog::app, " register EC in ThreadTeam"); + res = tt.tryRunEC(pl, ec).wait(); + TEST(res); + res = myCS.move(pl, tt.cap(), max_cap_depth, cs.cap(), init::THREAD_TEAM, max_cap_depth).wait(); TEST(res); + capAlloc.freeEmpty(tt.cap()); /* create portal */ MLOG_DETAIL(mlog::app, "create Portal ..."); From f1a8648a246a634e11a42b2b9db71da0202510ca Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Fri, 29 Jan 2021 15:09:29 +0100 Subject: [PATCH 05/42] remove ThreadTeam dependency in Schedulingcontext --- .../objects/SchedulingContext.hh | 10 ++++-- .../objects/thread-team/objects/ThreadTeam.cc | 36 ++++++------------- .../objects/thread-team/objects/ThreadTeam.hh | 14 ++++---- 3 files changed, 24 insertions(+), 36 deletions(-) diff --git a/kernel/objects/scheduling-context/objects/SchedulingContext.hh b/kernel/objects/scheduling-context/objects/SchedulingContext.hh index 6fe3f74b..a713c38b 100644 --- a/kernel/objects/scheduling-context/objects/SchedulingContext.hh +++ b/kernel/objects/scheduling-context/objects/SchedulingContext.hh @@ -32,10 +32,14 @@ #include #include "util/error-trace.hh" #include "util/events.hh" -#include "objects/ThreadTeam.hh" namespace mythos { + class INotifyIdle{ + public: + virtual void notifyIdle(Tasklet* t, cpu::ThreadID id) = 0; + }; + /** Scheduler for multiple application threads on a single hardware * thread. It implements an cooperative FIFO strategy that switches only * when the currently selected application thread becomes blocked. @@ -91,7 +95,7 @@ namespace mythos { void ready(handle_t* ec_handle) override; public: //ThreadTeam - void registerThreadTeam(ThreadTeam* tt){ + void registerThreadTeam(INotifyIdle* tt){ myTeam.store(tt); }; @@ -109,7 +113,7 @@ namespace mythos { std::atomic current_handle = {nullptr}; //< the currently selected execution context Tasklet paTask; //task for communication with processor allocator - std::atomic myTeam; + std::atomic myTeam; }; namespace event { diff --git a/kernel/objects/thread-team/objects/ThreadTeam.cc b/kernel/objects/thread-team/objects/ThreadTeam.cc index 314a63d8..e0e830e0 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.cc +++ b/kernel/objects/thread-team/objects/ThreadTeam.cc @@ -59,11 +59,6 @@ namespace mythos { } ); } -/* IResult */ - void ThreadTeam::response(Tasklet* /*t*/, optional res){ - MLOG_DETAIL(mlog::pm, "revoke response:", res.state()); - } - /* ThreadTeam */ ThreadTeam::ThreadTeam(IAsyncFree* memory) : memory(memory) @@ -71,7 +66,7 @@ namespace mythos { , nUsed(0) {} - void ThreadTeam::tryRunEC(ExecutionContext* ec){ + bool ThreadTeam::tryRunEC(ExecutionContext* ec){ MLOG_DETAIL(mlog::pm, __func__); auto pal = pa.get(); ASSERT(pal); @@ -86,13 +81,19 @@ namespace mythos { if(id){ auto sce = pal->getSC(*id); TypedCap sc(sce->cap()); - sc->registerThreadTeam(this); + sc->registerThreadTeam(static_cast(this)); pushUsed(*id); auto ret = ec->setSchedulingContext(sce); - MLOG_DETAIL(mlog::pm, "Init EC bind SC", DVAR(*id)); + if(ret){ + MLOG_DETAIL(mlog::pm, "Init EC bind SC", DVAR(*id)); + return true; + }else{ + MLOG_ERROR(mlog::pm, "ERROR: Init EC bind SC failed ", DVAR(*id)); + } }else{ MLOG_ERROR(mlog::pm, "Cannot allocate SC for init EC"); } + return false; } Error ThreadTeam::invokeTryRunEC(Tasklet* t, Cap, IInvocation* msg){ @@ -107,23 +108,8 @@ namespace mythos { TypedCap ec(ece); - auto pal = pa.get(); - ASSERT(pal); - auto id = popFree(); - if(id){ - MLOG_DETAIL(mlog::pm, "take SC from Team ", DVAR(*id)); - }else{ - MLOG_DETAIL(mlog::pm, "try alloc SC from PA"); - id = pal->alloc(); - } - if(id){ - MLOG_DETAIL(mlog::pm, "allocated thread id ", DVAR(*id)); - auto sce = pal->getSC(*id); - TypedCap sc(sce->cap()); - sc->registerThreadTeam(this); - pushUsed(*id); - auto ret = ec->setSchedulingContext(sce); - return ret.state(); + if(ec && tryRunEC(*ec)){ + return Error::SUCCESS; } return Error::INSUFFICIENT_RESOURCES; } diff --git a/kernel/objects/thread-team/objects/ThreadTeam.hh b/kernel/objects/thread-team/objects/ThreadTeam.hh index 048cfd2b..d6d9a6ea 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.hh +++ b/kernel/objects/thread-team/objects/ThreadTeam.hh @@ -34,13 +34,13 @@ #include "objects/RevokeOperation.hh" #include "objects/ProcessorAllocator.hh" #include "objects/ExecutionContext.hh" -#include "async/IResult.hh" +#include "objects/SchedulingContext.hh" namespace mythos { class ThreadTeam : public IKernelObject - , public IResult + , public INotifyIdle { public: ThreadTeam(IAsyncFree* memory); @@ -54,10 +54,7 @@ namespace mythos { THROW(Error::TYPE_MISMATCH); } - /* IResult */ - void response(Tasklet* /*t*/, optional res) override; - - void tryRunEC(ExecutionContext* ec); + bool tryRunEC(ExecutionContext* ec); Error invokeTryRunEC(Tasklet* t, Cap, IInvocation* msg); Error invokeDemandRunEC(Tasklet* t, Cap, IInvocation* msg); Error invokeForceRunEC(Tasklet* t, Cap, IInvocation* msg); @@ -71,7 +68,7 @@ namespace mythos { MLOG_ERROR(mlog::pm, "ERROR: unbind processor allocator"); } - void notifyIdle(Tasklet* t, cpu::ThreadID id){ + void notifyIdle(Tasklet* t, cpu::ThreadID id) override { MLOG_DETAIL(mlog::pm, __func__, DVAR(id)); monitor.request(t, [=](Tasklet* t){ removeUsed(id); @@ -117,6 +114,8 @@ namespace mythos { } + private: + IAsyncFree* memory; async::NestedMonitorDelegating monitor; friend class ThreadTeamFactory; @@ -126,7 +125,6 @@ namespace mythos { cpu::ThreadID usedList[MYTHOS_MAX_THREADS]; unsigned nUsed; - IAsyncFree* memory; }; class ThreadTeamFactory : public FactoryBase From 4a4cd4834c9bfbeb7c75fdf29cab0286ba45e294 Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Fri, 29 Jan 2021 15:47:22 +0100 Subject: [PATCH 06/42] fixed warnings --- kernel/objects/thread-team/objects/ThreadTeam.cc | 8 ++++---- kernel/objects/thread-team/objects/ThreadTeam.hh | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/kernel/objects/thread-team/objects/ThreadTeam.cc b/kernel/objects/thread-team/objects/ThreadTeam.cc index e0e830e0..11d02ff7 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.cc +++ b/kernel/objects/thread-team/objects/ThreadTeam.cc @@ -96,7 +96,7 @@ namespace mythos { return false; } - Error ThreadTeam::invokeTryRunEC(Tasklet* t, Cap, IInvocation* msg){ + Error ThreadTeam::invokeTryRunEC(Tasklet* /*t*/, Cap, IInvocation* msg){ MLOG_ERROR(mlog::pm, __func__); auto data = msg->getMessage()->read(); @@ -114,17 +114,17 @@ namespace mythos { return Error::INSUFFICIENT_RESOURCES; } - Error ThreadTeam::invokeDemandRunEC(Tasklet* t, Cap, IInvocation* msg){ + Error ThreadTeam::invokeDemandRunEC(Tasklet* /*t*/, Cap, IInvocation* /*msg*/){ MLOG_ERROR(mlog::pm, __func__, " NYI!"); return Error::NOT_IMPLEMENTED; } - Error ThreadTeam::invokeForceRunEC(Tasklet* t, Cap, IInvocation* msg){ + Error ThreadTeam::invokeForceRunEC(Tasklet* /*t*/, Cap, IInvocation* /*msg*/){ MLOG_ERROR(mlog::pm, __func__, " NYI!"); return Error::NOT_IMPLEMENTED; } - Error ThreadTeam::invokeRunNextToEC(Tasklet* t, Cap, IInvocation* msg){ + Error ThreadTeam::invokeRunNextToEC(Tasklet* /*t*/, Cap, IInvocation* /*msg*/){ MLOG_ERROR(mlog::pm, __func__, " NYI!"); return Error::NOT_IMPLEMENTED; } diff --git a/kernel/objects/thread-team/objects/ThreadTeam.hh b/kernel/objects/thread-team/objects/ThreadTeam.hh index d6d9a6ea..b687845e 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.hh +++ b/kernel/objects/thread-team/objects/ThreadTeam.hh @@ -70,7 +70,7 @@ namespace mythos { void notifyIdle(Tasklet* t, cpu::ThreadID id) override { MLOG_DETAIL(mlog::pm, __func__, DVAR(id)); - monitor.request(t, [=](Tasklet* t){ + monitor.request(t, [=](Tasklet*){ removeUsed(id); pushFree(id); monitor.responseAndRequestDone(); From 9282699909f894dd699bd5486a343b07cce00a2a Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Thu, 4 Feb 2021 14:29:58 +0100 Subject: [PATCH 07/42] local Portal --- kernel/app/init-example/app/init.cc | 82 +++++++++++++++---- .../process_test/process_test/process_test.cc | 1 + kernel/mythos/infoFrame/mythos/InfoFrame.hh | 15 +++- .../objects/thread-team/objects/ThreadTeam.cc | 2 +- kernel/runtime/cxx/runtime/cxxsupport.cc | 42 +++++++--- kernel/runtime/cxx/runtime/pthread.cc | 4 + kernel/runtime/memory/runtime/tls.cc | 5 ++ kernel/runtime/memory/runtime/tls.hh | 1 + kernel/runtime/process/runtime/process.hh | 14 ++-- 9 files changed, 129 insertions(+), 37 deletions(-) diff --git a/kernel/app/init-example/app/init.cc b/kernel/app/init-example/app/init.cc index 372b2947..75ad4acc 100644 --- a/kernel/app/init-example/app/init.cc +++ b/kernel/app/init-example/app/init.cc @@ -69,6 +69,7 @@ char initstack[stacksize]; char* initstack_top = initstack+stacksize; mythos::Portal portal(mythos::init::PORTAL, info_ptr->getInvocationBuf()); +mythos::Frame infoFrame(mythos::init::INFO_FRAME); mythos::CapMap myCS(mythos::init::CSPACE); mythos::PageMap myAS(mythos::init::PML4); mythos::KernelMemory kmem(mythos::init::KM); @@ -385,6 +386,47 @@ void test_InterruptControl() { MLOG_INFO(mlog::app, "test_InterruptControl end"); } +long SerialFib( long n ) { + if( n<2 ) + return n; + else + return SerialFib(n-1)+SerialFib(n-2); +} + +class FibTask: public tbb::task { +public: + const long n; + long* const sum; + FibTask( long n_, long* sum_ ) : + n(n_), sum(sum_) + {} + tbb::task* execute() { // Overrides virtual function task::execute + if( n<10 ) { + *sum = SerialFib(n); + } else { + long x, y; + FibTask& a = *new( allocate_child() ) FibTask(n-1,&x); + FibTask& b = *new( allocate_child() ) FibTask(n-2,&y); + // Set ref_count to 'two children plus one for the wait". + set_ref_count(3); + // Start b running. + spawn( b ); + // Start a running and wait for all children (a and b). + spawn_and_wait_for_all(a); + // Do the sum + *sum = x+y; + } + return NULL; + } +}; + +long ParallelFib( long n ) { + long sum; + FibTask& a = *new(tbb::task::allocate_root()) FibTask(n,&sum); + tbb::task::spawn_root_and_wait(a); + return sum; +} + void test_TBB(){ MLOG_INFO(mlog::app, "Test TBB"); @@ -399,11 +441,24 @@ void test_TBB(){ } }; - tbb::task_group tg; - for(int i=0; i<10; i++){ - tg.run(say_hello(i)); // spawn 1st task and return - } - tg.wait( ); // wait for tasks to complete + + MLOG_INFO(mlog::app, "fib", DVAR(ParallelFib(20))); + + //tbb::task_group tg; + //printf("created task group\n"); + //for(int i=0; i<10; i++){ + //tg.run(say_hello(i)); // spawn 1st task and return + //} + //tg.wait( ); // wait for tasks to complete + //tbb::parallel_for( tbb::blocked_range(0,3), + //[&](tbb::blocked_range r) + //{ + //for (int i=r.begin(); igetInvocationBuf()); +mythos::Frame infoFrame(mythos::init::INFO_FRAME); mythos::CapMap myCS(mythos::init::CSPACE); mythos::PageMap myAS(mythos::init::PML4); mythos::KernelMemory kmem(mythos::init::KM); diff --git a/kernel/mythos/infoFrame/mythos/InfoFrame.hh b/kernel/mythos/infoFrame/mythos/InfoFrame.hh index d467105b..28ffcb28 100644 --- a/kernel/mythos/infoFrame/mythos/InfoFrame.hh +++ b/kernel/mythos/infoFrame/mythos/InfoFrame.hh @@ -26,11 +26,13 @@ #pragma once #include "mythos/InvocationBuf.hh" - -#define PS_PER_TSC_DEFAULT (0x180) +#include "mythos/init.hh" namespace mythos { +constexpr uint64_t PS_PER_TSC_DEFAULT = 0x180; +constexpr size_t MAX_IB = 4096; + class InfoFrame{ public: InfoFrame() @@ -38,12 +40,17 @@ class InfoFrame{ , numThreads(1) {} - InvocationBuf* getInvocationBuf() {return &ib; } + InvocationBuf* getInvocationBuf() {return &ib[0]; } + InvocationBuf* getInvocationBuf(size_t i) {return &ib[i]; } + size_t getIbOffset(size_t i){ + return reinterpret_cast(&ib[i]) - reinterpret_cast(this); + } + uint64_t getPsPerTSC() { return psPerTsc; } size_t getNumThreads() { return numThreads; } uintptr_t getInfoEnd () { return reinterpret_cast(this) + sizeof(InfoFrame); } - InvocationBuf ib; // needs to be the first member (see Initloader::createPortal) + InvocationBuf ib[MAX_IB]; // needs to be the first member (see Initloader::createPortal) uint64_t psPerTsc; // picoseconds per time stamp counter size_t numThreads; // number of hardware threads available in the system }; diff --git a/kernel/objects/thread-team/objects/ThreadTeam.cc b/kernel/objects/thread-team/objects/ThreadTeam.cc index 11d02ff7..60dfb1e7 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.cc +++ b/kernel/objects/thread-team/objects/ThreadTeam.cc @@ -91,7 +91,7 @@ namespace mythos { MLOG_ERROR(mlog::pm, "ERROR: Init EC bind SC failed ", DVAR(*id)); } }else{ - MLOG_ERROR(mlog::pm, "Cannot allocate SC for init EC"); + MLOG_WARN(mlog::pm, "Cannot allocate SC for EC"); } return false; } diff --git a/kernel/runtime/cxx/runtime/cxxsupport.cc b/kernel/runtime/cxx/runtime/cxxsupport.cc index cf8d247a..2b477edd 100644 --- a/kernel/runtime/cxx/runtime/cxxsupport.cc +++ b/kernel/runtime/cxx/runtime/cxxsupport.cc @@ -58,17 +58,31 @@ extern mythos::InfoFrame* info_ptr asm("info_ptr"); extern mythos::Portal portal; +extern mythos::Frame infoFrame; extern mythos::CapMap myCS; extern mythos::PageMap myAS; extern mythos::KernelMemory kmem; extern mythos::ThreadTeam team; +static thread_local mythos::CapPtr localPortalPtr; +thread_local mythos::Portal localPortal( + mythos_get_pthread_ec_self() == mythos::init::EC ? mythos::init::PORTAL : localPortalPtr, + mythos_get_pthread_ec_self() == mythos::init::EC ? info_ptr->getInvocationBuf() + : info_ptr->getInvocationBuf(localPortalPtr)); + +void setRemotePortalPtr(uintptr_t targetTLS, mythos::CapPtr p){ + auto ptr = reinterpret_cast(targetTLS + - (mythos::getTLS() - reinterpret_cast(&localPortalPtr))); + *ptr = p; +} + + // synchronization for pthread deletion (exit/join) struct PthreadCleaner{ PthreadCleaner() : flag(FREE) { - //MLOG_ERROR(mlog::app, "PthreadCleaner"); + MLOG_DETAIL(mlog::app, "PthreadCleaner"); } enum state{ @@ -150,9 +164,7 @@ int prlimit( int my_sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask) { //MLOG_DETAIL(mlog::app, "syscall sched_setaffinity", DVAR(pid), DVAR(cpusetsize), DVARhex(mask)); - //todo: make TBB and OMP ressource aware (pthread_create fail) - //if(cpusetsize == info_ptr->getNumThreads() && mask == NULL) return -EFAULT; - if(cpusetsize == 2 && mask == NULL) return -EFAULT; + if(cpusetsize == 8/*info_ptr->getNumThreads()*/ && mask == NULL) return -EFAULT; return 0; } @@ -162,10 +174,9 @@ int my_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask) if (mask) { //CPU_ZERO(mask); memset(mask, 0, cpusetsize); - for(int i = 0; i < 2 /*info_ptr->getNumThreads()*/; i++) CPU_SET(i, mask); + for(int i = 0; i < 8/*info_ptr->getNumThreads()*/; i++) CPU_SET(i, mask); } - //todo: make TBB and OMP ressource aware (pthread_create fail) - return 2;//info_ptr->getNumThreads(); + return 8/*info_ptr->getNumThreads()*/; } void clock_gettime(long clk, struct timespec *ts){ @@ -317,15 +328,15 @@ int myclone( void *arg, int* ptid, void* tls, int* ctid) { MLOG_DETAIL(mlog::app, "myclone"); + setRemotePortalPtr(reinterpret_cast(tls), 42); ASSERT(tls != nullptr); - // The compiler expect a kinda strange alignment coming from clone: // -> rsp % 16 must be 8 // You can see this also in musl/src/thread/x86_64/clone.s (rsi is stack) // We will use the same trick for alignment as musl libc auto rsp = (uintptr_t(stack) & uintptr_t(-16))-8; - mythos::PortalLock pl(portal); // future access will fail if the portal is in use already + mythos::PortalLock pl(localPortal); // future access will fail if the portal is in use already mythos::ExecutionContext ec(capAlloc()); if (ptid && (flags&CLONE_PARENT_SETTID)) *ptid = int(ec.cap()); // @todo store thread-specific ctid pointer, which should set to 0 by the OS on the thread's exit @@ -333,13 +344,22 @@ int myclone( auto res = ec.create(kmem) .as(myAS) .cs(myCS) - //.sched(sc->cap) .rawStack(rsp) .rawFun(func, arg) .suspended(false) .fs(tls) .invokeVia(pl) .wait(); + + // create Portal + ASSERT(ec.cap() < mythos::MAX_IB); + mythos::CapPtr pPtr = capAlloc(); + mythos::Portal newPortal(pPtr, info_ptr->getInvocationBuf(pPtr)); + newPortal.create(pl, kmem).wait(); + newPortal.bind(pl, infoFrame, info_ptr->getIbOffset(pPtr), ec.cap()); + setRemotePortalPtr(reinterpret_cast(tls), pPtr); + MLOG_WARN(mlog::app, "todo: free Portal!"); + auto tres = team.tryRunEC(pl, ec).wait(); if(tres){ return ec.cap(); @@ -368,7 +388,7 @@ extern "C" void mythos_pthread_cleanup(pthread_t t){ pthreadCleaner.wait(t); // delete EC of target pthread auto cap = mythos_get_pthread_ec(t); - mythos::PortalLock pl(portal); + mythos::PortalLock pl(localPortal); capAlloc.free(cap, pl); // memory of target pthread will be free when returning from this function } diff --git a/kernel/runtime/cxx/runtime/pthread.cc b/kernel/runtime/cxx/runtime/pthread.cc index 1f55ef10..43bbbae4 100644 --- a/kernel/runtime/cxx/runtime/pthread.cc +++ b/kernel/runtime/cxx/runtime/pthread.cc @@ -453,10 +453,12 @@ extern "C" int pthread_attr_setinheritsched(pthread_attr_t *, int){ } +#ifdef use_pthreads_stubs extern "C" int pthread_mutexattr_destroy(pthread_mutexattr_t *){ MLOG_ERROR(mlog::app, __PRETTY_FUNCTION__); return 0; } +#endif extern "C" int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *__restrict, int *__restrict){ MLOG_ERROR(mlog::app, __PRETTY_FUNCTION__); @@ -510,10 +512,12 @@ extern "C" int pthread_mutexattr_setrobust(pthread_mutexattr_t *, int){ return 0; } +#ifdef use_pthreads_stubs extern "C" int pthread_mutexattr_settype(pthread_mutexattr_t *, int){ MLOG_ERROR(mlog::app, __PRETTY_FUNCTION__); return 0; } +#endif #ifdef use_pthreads_stubs diff --git a/kernel/runtime/memory/runtime/tls.cc b/kernel/runtime/memory/runtime/tls.cc index fb66367b..766d6008 100644 --- a/kernel/runtime/memory/runtime/tls.cc +++ b/kernel/runtime/memory/runtime/tls.cc @@ -133,4 +133,9 @@ void* setupNewTLS() { return tcbAddr; } +uintptr_t getTLS() { + uintptr_t val; + asm volatile ( "movq %%fs:0, %0" : "=r"(val) ); + return val; +} } // namespace mythos diff --git a/kernel/runtime/memory/runtime/tls.hh b/kernel/runtime/memory/runtime/tls.hh index d8638bdf..8789c983 100644 --- a/kernel/runtime/memory/runtime/tls.hh +++ b/kernel/runtime/memory/runtime/tls.hh @@ -35,4 +35,5 @@ void setupInitialTLS(); void* setupNewTLS(); +uintptr_t getTLS(); } // namespace mythos diff --git a/kernel/runtime/process/runtime/process.hh b/kernel/runtime/process/runtime/process.hh index 2b02b041..cdcc989f 100644 --- a/kernel/runtime/process/runtime/process.hh +++ b/kernel/runtime/process/runtime/process.hh @@ -247,11 +247,11 @@ class Process{ MLOG_DETAIL(mlog::app, "create InfoFrame ..."); auto size = round_up(sizeof(InfoFrame), align2M); MLOG_DETAIL(mlog::app, " create frame", DVAR(size)); - Frame infoFrame(capAlloc()); - res = infoFrame.create(pl, kmem, size, align2M).wait(); + Frame iFrame(capAlloc()); + res = iFrame.create(pl, kmem, size, align2M).wait(); TEST(res); MLOG_DETAIL(mlog::app, " map frame to target page map", DVARhex(size), DVARhex(*ipc_vaddr)); - res = pm4.mmap(pl, infoFrame, *ipc_vaddr, align2M, 0x1).wait(); + res = pm4.mmap(pl, iFrame, *ipc_vaddr, align2M, 0x1).wait(); TEST(res); uintptr_t tmp_vaddr_if = 11*align512G; @@ -271,7 +271,7 @@ class Process{ TEST(res); MLOG_DETAIL(mlog::app, " mmap"); - res = myAS.mmap(pl, infoFrame, tmp_vaddr_if, size, 0x1).wait(); + res = myAS.mmap(pl, iFrame, tmp_vaddr_if, size, 0x1).wait(); TEST(res); MLOG_DETAIL(mlog::app, " copy info frame content"); @@ -321,7 +321,7 @@ class Process{ Portal port(capAlloc(), reinterpret_cast(*ipc_vaddr)); res = port.create(pl, kmem).wait(); TEST(res); - res = port.bind(pl, infoFrame, 0, ec.cap()).wait(); + res = port.bind(pl, iFrame, 0, ec.cap()).wait(); TEST(res); MLOG_DETAIL(mlog::app, " move Portal"); @@ -330,9 +330,9 @@ class Process{ capAlloc.freeEmpty(port.cap()); MLOG_DETAIL(mlog::app, " move info frame"); - res = myCS.move(pl, infoFrame.cap(), max_cap_depth, cs.cap(), init::INFO_FRAME, max_cap_depth).wait(); + res = myCS.move(pl, iFrame.cap(), max_cap_depth, cs.cap(), init::INFO_FRAME, max_cap_depth).wait(); TEST(res); - capAlloc.freeEmpty(infoFrame.cap()); + capAlloc.freeEmpty(iFrame.cap()); /* move tables */ MLOG_DETAIL(mlog::app, "move tables ..."); From 25e503081c749ab73225e279cea2fa1c9a0ba49a Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Sun, 7 Feb 2021 22:19:56 +0100 Subject: [PATCH 08/42] worked on ThreadTeam --- .../thread-team/mythos/protocol/ThreadTeam.hh | 76 +++++++++++-------- .../objects/thread-team/objects/ThreadTeam.cc | 50 ++++++++++-- .../objects/thread-team/objects/ThreadTeam.hh | 40 +++++++++- kernel/runtime/kobject/runtime/ThreadTeam.hh | 14 +--- 4 files changed, 127 insertions(+), 53 deletions(-) diff --git a/kernel/objects/thread-team/mythos/protocol/ThreadTeam.hh b/kernel/objects/thread-team/mythos/protocol/ThreadTeam.hh index 0dcc809b..6d623c55 100644 --- a/kernel/objects/thread-team/mythos/protocol/ThreadTeam.hh +++ b/kernel/objects/thread-team/mythos/protocol/ThreadTeam.hh @@ -39,14 +39,18 @@ namespace mythos { enum Methods : uint8_t { TRYRUNEC, RETTRYRUNEC, - DEMANDRUNEC, - RETDEMANDRUNEC, - FORCERUNEC, - RETFORCERUNEC, + REVOKEDEMAND, + RETREVOKEDEMAND, RUNNEXTTOEC, RETRUNNEXTTOEC }; + enum TeamAllocType{ + FAIL = 0, + FORCE = 1, + DEMAND = 2 + }; + struct Create : public KernelMemory::CreateBase { typedef InvocationBase response_type; //constexpr static uint16_t label = (proto<<8) + CREATE; @@ -60,39 +64,46 @@ namespace mythos { struct TryRunEC : public InvocationBase { constexpr static uint16_t label = (proto<<8) + TRYRUNEC; - TryRunEC(CapPtr ec) : InvocationBase(label,getLength(this)) { + TryRunEC(CapPtr ec, int allocType) + : InvocationBase(label,getLength(this)) + , allocType(allocType) + { addExtraCap(ec); } // execution context to be scheduled CapPtr ec() const { return this->capPtrs[0]; } + int allocType; }; struct RetTryRunEC : public InvocationBase { constexpr static uint16_t label = (proto<<8) + RETTRYRUNEC; - RetTryRunEC() : InvocationBase(label,getLength(this)) { - } - }; - - struct DemandRunEC : public InvocationBase { - constexpr static uint16_t label = (proto<<8) + DEMANDRUNEC; - DemandRunEC(CapPtr ec) : InvocationBase(label,getLength(this)) { - addExtraCap(ec); - } - // execution context to be scheduled - CapPtr ec() const { return this->capPtrs[0]; } - }; - - struct RetDemandRunEC : public InvocationBase { - constexpr static uint16_t label = (proto<<8) + RETDEMANDRUNEC; - RetDemandRunEC() : InvocationBase(label,getLength(this)) { - } + enum response{ + FAILED, + ALLOCATED, + DEMANDED, + FORCED + }; + + RetTryRunEC() + : InvocationBase(label,getLength(this)) + , response(FAILED) + {} + + void setResponse(int response){ this->response = response; } + int getResponse() { return response; } + bool failed() { return response == FAILED; } + bool allocated() { return response == ALLOCATED; } + bool notFailed() { return response == ALLOCATED || response == DEMANDED + || response == FORCED; } + int response; }; - struct ForceRunEC : public InvocationBase { - constexpr static uint16_t label = (proto<<8) + FORCERUNEC; - ForceRunEC(CapPtr ec) : InvocationBase(label,getLength(this)) { + struct RevokeDemand : public InvocationBase { + constexpr static uint16_t label = (proto<<8) + REVOKEDEMAND; + RevokeDemand(CapPtr ec) : InvocationBase(label,getLength(this)) + { addExtraCap(ec); } @@ -100,10 +111,14 @@ namespace mythos { CapPtr ec() const { return this->capPtrs[0]; } }; - struct RetForceRunEC : public InvocationBase { - constexpr static uint16_t label = (proto<<8) + RETFORCERUNEC; - RetForceRunEC() : InvocationBase(label,getLength(this)) { - } + struct RetRevokeDemand : public InvocationBase { + constexpr static uint16_t label = (proto<<8) + RETREVOKEDEMAND; + RetRevokeDemand() + : InvocationBase(label,getLength(this)) + , revoked(false) + {} + + bool revoked; }; struct RunNextToEC : public InvocationBase { @@ -128,8 +143,7 @@ namespace mythos { static Error dispatchRequest(IMPL* obj, uint8_t m, ARGS const&...args) { switch(Methods(m)) { case TRYRUNEC: return obj->invokeTryRunEC(args...); - case DEMANDRUNEC: return obj->invokeDemandRunEC(args...); - case FORCERUNEC: return obj->invokeForceRunEC(args...); + case REVOKEDEMAND: return obj->invokeRevokeDemand(args...); case RUNNEXTTOEC: return obj->invokeRunNextToEC(args...); default: return Error::NOT_IMPLEMENTED; } diff --git a/kernel/objects/thread-team/objects/ThreadTeam.cc b/kernel/objects/thread-team/objects/ThreadTeam.cc index 11d02ff7..5a9caac1 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.cc +++ b/kernel/objects/thread-team/objects/ThreadTeam.cc @@ -64,6 +64,7 @@ namespace mythos { : memory(memory) , nFree(0) , nUsed(0) + , nDemand(0) {} bool ThreadTeam::tryRunEC(ExecutionContext* ec){ @@ -101,6 +102,7 @@ namespace mythos { auto data = msg->getMessage()->read(); auto ece = msg->lookupEntry(data.ec()); + auto ret = msg->getMessage()->cast(); if(!ece){ MLOG_ERROR(mlog::pm, "Error: Did not find EC!"); return Error::INVALID_CAPABILITY; @@ -109,19 +111,51 @@ namespace mythos { TypedCap ec(ece); if(ec && tryRunEC(*ec)){ + ret->setResponse(protocol::ThreadTeam::RetTryRunEC::ALLOCATED); return Error::SUCCESS; } - return Error::INSUFFICIENT_RESOURCES; - } - Error ThreadTeam::invokeDemandRunEC(Tasklet* /*t*/, Cap, IInvocation* /*msg*/){ - MLOG_ERROR(mlog::pm, __func__, " NYI!"); - return Error::NOT_IMPLEMENTED; + if(data.allocType == protocol::ThreadTeam::DEMAND){ + if(enqueueDemand(ec)){ + ret->setResponse(protocol::ThreadTeam::RetTryRunEC::DEMANDED); + return Error::SUCCESS; + } + }else if(data.allocType == protocol::ThreadTeam::FORCE){ + //todo: force run + if(nUsed > 0){ + //todo: use a more sophisticated mapping scheme + auto pal = pa.get(); + ASSERT(pal); + auto sce = pal->getSC(usedList[0]); + auto r = ec->setSchedulingContext(sce); + if(r){ + ret->setResponse(protocol::ThreadTeam::RetTryRunEC::FORCED); + return Error::SUCCESS; + } + } + } + + ret->setResponse(protocol::ThreadTeam::RetTryRunEC::FAILED); + return Error::SUCCESS; } - Error ThreadTeam::invokeForceRunEC(Tasklet* /*t*/, Cap, IInvocation* /*msg*/){ - MLOG_ERROR(mlog::pm, __func__, " NYI!"); - return Error::NOT_IMPLEMENTED; + Error ThreadTeam::invokeRevokeDemand(Tasklet* /*t*/, Cap, IInvocation* msg){ + MLOG_DETAIL(mlog::pm, __func__); + auto data = msg->getMessage()->read(); + auto ece = msg->lookupEntry(data.ec()); + auto ret = msg->getMessage()->cast(); + if(!ece){ + MLOG_ERROR(mlog::pm, "Error: Did not find EC!"); + return Error::INVALID_CAPABILITY; + } + + TypedCap ec(ece); + if(removeDemand(ece)){ + ret->revoked = true; + } + + ret->revoked = false; + return Error::SUCCESS; } Error ThreadTeam::invokeRunNextToEC(Tasklet* /*t*/, Cap, IInvocation* /*msg*/){ diff --git a/kernel/objects/thread-team/objects/ThreadTeam.hh b/kernel/objects/thread-team/objects/ThreadTeam.hh index b687845e..9b960b93 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.hh +++ b/kernel/objects/thread-team/objects/ThreadTeam.hh @@ -56,8 +56,7 @@ namespace mythos { bool tryRunEC(ExecutionContext* ec); Error invokeTryRunEC(Tasklet* t, Cap, IInvocation* msg); - Error invokeDemandRunEC(Tasklet* t, Cap, IInvocation* msg); - Error invokeForceRunEC(Tasklet* t, Cap, IInvocation* msg); + Error invokeRevokeDemand(Tasklet* t, Cap, IInvocation* msg); Error invokeRunNextToEC(Tasklet* t, Cap, IInvocation* msg); void bind(optional ) { @@ -113,6 +112,40 @@ namespace mythos { MLOG_ERROR(mlog::pm, "ERROR: did not find used ThreadID ", id); } + bool enqueueDemand(TypedCap ec){ + if(nDemand < MYTHOS_MAX_THREADS){ + demandList[nDemand] = ec; + nDemand++; + return true; + } + return false; + } + + bool removeDemand(TypedCap ec){ + for(unsigned i = 0; i < nDemand; i++){ + if(demandList[i].obj() == ec.obj()){ + nDemand--; + for(; i < nDemand; i++){ + demandList[i] = demandList[i+1]; + } + return true; + } + } + MLOG_WARN(mlog::pm, "did not find EC in demand list "); + return false; + } + + TypedCap dequeueDemand(){ + if(nDemand){ + auto ret = demandList[0]; + nDemand--; + for(unsigned i = 0; i < nDemand; i++){ + demandList[i] = demandList[i+1]; + } + return ret; + } + return TypedCap(); + } private: IAsyncFree* memory; @@ -124,7 +157,8 @@ namespace mythos { unsigned nFree; cpu::ThreadID usedList[MYTHOS_MAX_THREADS]; unsigned nUsed; - + TypedCap demandList[MYTHOS_MAX_THREADS]; + unsigned nDemand; }; class ThreadTeamFactory : public FactoryBase diff --git a/kernel/runtime/kobject/runtime/ThreadTeam.hh b/kernel/runtime/kobject/runtime/ThreadTeam.hh index 6080b9af..5e53bd73 100644 --- a/kernel/runtime/kobject/runtime/ThreadTeam.hh +++ b/kernel/runtime/kobject/runtime/ThreadTeam.hh @@ -43,24 +43,16 @@ namespace mythos { return pr.invoke(kmem.cap(), _cap, factory, pa); } - PortalFuture tryRunEC(PortalLock pr, ExecutionContext ec){ - return pr.invoke(_cap, ec.cap()); + PortalFuture tryRunEC(PortalLock pr, ExecutionContext ec, int at = protocol::ThreadTeam::FAIL){ + return pr.invoke(_cap, ec.cap(), at); } PortalFuture runNextToEC(PortalLock pr, ExecutionContext ec, ExecutionContext ec_place){ return pr.invoke(_cap, ec.cap(), ec_place.cap()); } - PortalFuture demandRunEC(PortalLock pr, ExecutionContext ec){ - return pr.invoke(_cap, ec.cap()); - } - PortalFuture revokeDemand(PortalLock pr, ExecutionContext ec){ - return pr.invoke(_cap, ec.cap()); - } - - PortalFuture forceRunEC(PortalLock pr, ExecutionContext ec){ - return pr.invoke(_cap, ec.cap()); + return pr.invoke(_cap, ec.cap()); } }; From ac226d7af246da359ce6a40c9c7524e3515aacad Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Tue, 9 Feb 2021 13:25:42 +0100 Subject: [PATCH 09/42] worked on ThreadTeam --- .../thread-team/objects/PluginThreadTeam.hh | 2 +- .../objects/thread-team/objects/ThreadTeam.cc | 174 ++++++++++++++++-- .../objects/thread-team/objects/ThreadTeam.hh | 95 ++-------- 3 files changed, 177 insertions(+), 94 deletions(-) diff --git a/kernel/objects/thread-team/objects/PluginThreadTeam.hh b/kernel/objects/thread-team/objects/PluginThreadTeam.hh index b89acf21..3b03313e 100644 --- a/kernel/objects/thread-team/objects/PluginThreadTeam.hh +++ b/kernel/objects/thread-team/objects/PluginThreadTeam.hh @@ -90,7 +90,7 @@ namespace factory { void processEvent(ExecutionContext* ec) override { MLOG_DETAIL(mlog::pm, "runEc"); ASSERT(tt != nullptr); - tt->tryRunEC(ec); + tt->tryRun(ec); } ThreadTeam* tt; diff --git a/kernel/objects/thread-team/objects/ThreadTeam.cc b/kernel/objects/thread-team/objects/ThreadTeam.cc index 5a9caac1..4b5bd7c0 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.cc +++ b/kernel/objects/thread-team/objects/ThreadTeam.cc @@ -65,9 +65,13 @@ namespace mythos { , nFree(0) , nUsed(0) , nDemand(0) - {} + { + for(unsigned d = 0; d < MYTHOS_MAX_THREADS; d++){ + demandList[d] = d; + } + } - bool ThreadTeam::tryRunEC(ExecutionContext* ec){ + bool ThreadTeam::tryRun(ExecutionContext* ec){ MLOG_DETAIL(mlog::pm, __func__); auto pal = pa.get(); ASSERT(pal); @@ -79,24 +83,33 @@ namespace mythos { MLOG_DETAIL(mlog::pm, "try alloc SC from PA"); id = pal->alloc(); } - if(id){ - auto sce = pal->getSC(*id); - TypedCap sc(sce->cap()); - sc->registerThreadTeam(static_cast(this)); + if(id && tryRunAt(ec, *id)){ pushUsed(*id); - auto ret = ec->setSchedulingContext(sce); - if(ret){ - MLOG_DETAIL(mlog::pm, "Init EC bind SC", DVAR(*id)); - return true; - }else{ - MLOG_ERROR(mlog::pm, "ERROR: Init EC bind SC failed ", DVAR(*id)); - } + return true; }else{ MLOG_ERROR(mlog::pm, "Cannot allocate SC for init EC"); } return false; } + bool ThreadTeam::tryRunAt(ExecutionContext* ec, cpu::ThreadID id){ + MLOG_DETAIL(mlog::pm, __func__); + auto pal = pa.get(); + ASSERT(pal); + + auto sce = pal->getSC(id); + TypedCap sc(sce->cap()); + sc->registerThreadTeam(static_cast(this)); + auto ret = ec->setSchedulingContext(sce); + if(ret){ + MLOG_DETAIL(mlog::pm, "Init EC bind SC", DVAR(id)); + return true; + }else{ + MLOG_ERROR(mlog::pm, "ERROR: Init EC bind SC failed ", DVAR(id)); + } + return false; + } + Error ThreadTeam::invokeTryRunEC(Tasklet* /*t*/, Cap, IInvocation* msg){ MLOG_ERROR(mlog::pm, __func__); @@ -110,18 +123,17 @@ namespace mythos { TypedCap ec(ece); - if(ec && tryRunEC(*ec)){ + if(ec && tryRun(*ec)){ ret->setResponse(protocol::ThreadTeam::RetTryRunEC::ALLOCATED); return Error::SUCCESS; } if(data.allocType == protocol::ThreadTeam::DEMAND){ - if(enqueueDemand(ec)){ + if(enqueueDemand(*ece)){ ret->setResponse(protocol::ThreadTeam::RetTryRunEC::DEMANDED); return Error::SUCCESS; } }else if(data.allocType == protocol::ThreadTeam::FORCE){ - //todo: force run if(nUsed > 0){ //todo: use a more sophisticated mapping scheme auto pal = pa.get(); @@ -150,19 +162,144 @@ namespace mythos { } TypedCap ec(ece); - if(removeDemand(ece)){ + if(ec && removeDemand(*ec)){ ret->revoked = true; + }else{ + MLOG_WARN(mlog::pm, "revoke demand failed"); + ret->revoked = false; } - ret->revoked = false; return Error::SUCCESS; } + void ThreadTeam::notifyIdle(Tasklet* t, cpu::ThreadID id) { + MLOG_DETAIL(mlog::pm, __func__, DVAR(id)); + monitor.request(t, [=](Tasklet*){ + if(!tryRunDemandAt(id)) { + removeUsed(id); + pushFree(id); + } + monitor.responseAndRequestDone(); + }); + } + Error ThreadTeam::invokeRunNextToEC(Tasklet* /*t*/, Cap, IInvocation* /*msg*/){ MLOG_ERROR(mlog::pm, __func__, " NYI!"); return Error::NOT_IMPLEMENTED; } + void ThreadTeam::pushFree(cpu::ThreadID id){ + MLOG_DETAIL(mlog::pm, __func__, DVAR(id)); + freeList[nFree] = id; + nFree++; + } + + optional ThreadTeam::popFree(){ + MLOG_DETAIL(mlog::pm, __func__); + optional ret; + if(nFree > 0){ + nFree--; + ret = freeList[nFree]; + } + return ret; + } + + void ThreadTeam::pushUsed(cpu::ThreadID id){ + MLOG_DETAIL(mlog::pm, __func__, DVAR(id)); + usedList[nUsed] = id; + nUsed++; + } + + void ThreadTeam::removeUsed(cpu::ThreadID id){ + MLOG_DETAIL(mlog::pm, __func__, DVAR(id)); + for(unsigned i = 0; i < nUsed; i++){ + if(usedList[i] == id){ + nUsed--; + for(; i < nUsed; i++){ + usedList[i] = usedList[i+1]; + } + return; + } + } + MLOG_ERROR(mlog::pm, "ERROR: did not find used ThreadID ", id); + } + + bool ThreadTeam::enqueueDemand(CapEntry* ec){ + if(nDemand < MYTHOS_MAX_THREADS){ + demandEC[demandList[nDemand]].set(this, ec, ec->cap()); + nDemand++; + return true; + } + return false; + } + + bool ThreadTeam::removeDemand(ExecutionContext* ec){ + //find entry + for(unsigned i = 0; i < nDemand; i++){ + auto di = demandList[i]; + auto d = demandEC[di].get(); + if(d && *d == ec){ + demandEC[di].reset(); + nDemand--; + //move following entries + for(; i < nDemand; i++){ + demandList[i] = demandList[i+1]; + } + //move demand index behind used indexes + demandList[nDemand] = di; + return true; + } + } + MLOG_WARN(mlog::pm, "did not find EC in demand list "); + return false; + } + + //bool ThreadTeam::tryRunDemand() { + //// demand available? + //if(nDemand){ + ////take first + //auto di = demandList[0]; + //TypedCap ec(demandEC[di]); + //ASSERT(ec); + ////try to run ec + //if(tryRun(*ec)){ + ////reset CapRef + //demandEC[di].reset(); + //// remove from queue + //nDemand--; + //for(unsigned i = 0; i < nDemand; i++){ + //demandList[i] = demandList[i+1]; + //} + //demandList[nDemand] = di; + //return true; + //} + //} + //return false; + //} + + bool ThreadTeam::tryRunDemandAt(cpu::ThreadID id) { + // demand available? + if(nDemand){ + //take first + auto di = demandList[0]; + TypedCap ec(demandEC[di]); + ASSERT(ec); + //try to run ec + if(tryRunAt(*ec, id)){ + //reset CapRef + demandEC[di].reset(); + // remove from queue + nDemand--; + for(unsigned i = 0; i < nDemand; i++){ + demandList[i] = demandList[i+1]; + } + demandList[nDemand] = di; + return true; + } + } + return false; + } + optional ThreadTeamFactory::factory(CapEntry* dstEntry, CapEntry* memEntry, Cap memCap, IAllocator* mem, CapEntry* pae){ auto obj = mem->create(); @@ -181,4 +318,5 @@ namespace mythos { } return *obj; } + } // namespace mythos diff --git a/kernel/objects/thread-team/objects/ThreadTeam.hh b/kernel/objects/thread-team/objects/ThreadTeam.hh index 9b960b93..ca6a9de7 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.hh +++ b/kernel/objects/thread-team/objects/ThreadTeam.hh @@ -54,7 +54,8 @@ namespace mythos { THROW(Error::TYPE_MISMATCH); } - bool tryRunEC(ExecutionContext* ec); + bool tryRun(ExecutionContext* ec); + bool tryRunAt(ExecutionContext* ec, cpu::ThreadID id); Error invokeTryRunEC(Tasklet* t, Cap, IInvocation* msg); Error invokeRevokeDemand(Tasklet* t, Cap, IInvocation* msg); Error invokeRunNextToEC(Tasklet* t, Cap, IInvocation* msg); @@ -67,85 +68,26 @@ namespace mythos { MLOG_ERROR(mlog::pm, "ERROR: unbind processor allocator"); } - void notifyIdle(Tasklet* t, cpu::ThreadID id) override { - MLOG_DETAIL(mlog::pm, __func__, DVAR(id)); - monitor.request(t, [=](Tasklet*){ - removeUsed(id); - pushFree(id); - monitor.responseAndRequestDone(); - }); - } - private: - void pushFree(cpu::ThreadID id){ - MLOG_DETAIL(mlog::pm, __func__, DVAR(id)); - freeList[nFree] = id; - nFree++; - } + void bind(optional /*ec*/){} - optional popFree(){ + void unbind(optional ec){ MLOG_DETAIL(mlog::pm, __func__); - optional ret; - if(nFree > 0){ - nFree--; - ret = freeList[nFree]; - } - return ret; - } - - void pushUsed(cpu::ThreadID id){ - MLOG_DETAIL(mlog::pm, __func__, DVAR(id)); - usedList[nUsed] = id; - nUsed++; - } - - void removeUsed(cpu::ThreadID id){ - MLOG_DETAIL(mlog::pm, __func__, DVAR(id)); - for(unsigned i = 0; i < nUsed; i++){ - if(usedList[i] == id){ - nUsed--; - for(; i < nUsed; i++){ - usedList[i] = usedList[i+1]; - } - return; - } + if(ec){ + removeDemand(*ec); } - MLOG_ERROR(mlog::pm, "ERROR: did not find used ThreadID ", id); } - bool enqueueDemand(TypedCap ec){ - if(nDemand < MYTHOS_MAX_THREADS){ - demandList[nDemand] = ec; - nDemand++; - return true; - } - return false; - } - - bool removeDemand(TypedCap ec){ - for(unsigned i = 0; i < nDemand; i++){ - if(demandList[i].obj() == ec.obj()){ - nDemand--; - for(; i < nDemand; i++){ - demandList[i] = demandList[i+1]; - } - return true; - } - } - MLOG_WARN(mlog::pm, "did not find EC in demand list "); - return false; - } + void notifyIdle(Tasklet* t, cpu::ThreadID id) override; - TypedCap dequeueDemand(){ - if(nDemand){ - auto ret = demandList[0]; - nDemand--; - for(unsigned i = 0; i < nDemand; i++){ - demandList[i] = demandList[i+1]; - } - return ret; - } - return TypedCap(); - } + private: + void pushFree(cpu::ThreadID id); + optional popFree(); + void pushUsed(cpu::ThreadID id); + void removeUsed(cpu::ThreadID id); + bool enqueueDemand(CapEntry* ec); + bool removeDemand(ExecutionContext* ec); + //bool tryRunDemand(); + bool tryRunDemandAt(cpu::ThreadID id); private: IAsyncFree* memory; @@ -157,7 +99,10 @@ namespace mythos { unsigned nFree; cpu::ThreadID usedList[MYTHOS_MAX_THREADS]; unsigned nUsed; - TypedCap demandList[MYTHOS_MAX_THREADS]; + CapRef demandEC[MYTHOS_MAX_THREADS]; + // index < nDemand = demandEC slot in use + // index >= nDemand = demandEC slot is free + unsigned demandList[MYTHOS_MAX_THREADS]; // indexes to demandEC unsigned nDemand; }; From 2b2f8318af49068537e8ab5d1558b853ba60a593 Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Thu, 18 Feb 2021 18:55:03 +0100 Subject: [PATCH 10/42] threadteam synchronization --- 3rdparty/tbb | 2 +- Makefile.user | 2 +- kernel/app/init-example/app/init.cc | 38 +- .../objects/ExecutionContext.cc | 24 ++ .../objects/ExecutionContext.hh | 2 + .../objects/ProcessorAllocator.cc | 3 +- .../objects/ProcessorAllocator.hh | 16 +- .../objects/SchedulingContext.hh | 4 + .../thread-team/mythos/protocol/ThreadTeam.hh | 9 +- .../objects/thread-team/objects/ThreadTeam.cc | 374 ++++++++++++------ .../objects/thread-team/objects/ThreadTeam.hh | 57 ++- kernel/runtime/cxx/runtime/cxxsupport.cc | 178 +++++++-- .../runtime/kobject/runtime/SimpleCapAlloc.hh | 20 + kernel/runtime/kobject/runtime/ThreadTeam.hh | 28 +- 14 files changed, 546 insertions(+), 211 deletions(-) diff --git a/3rdparty/tbb b/3rdparty/tbb index dda6d323..efa9881d 160000 --- a/3rdparty/tbb +++ b/3rdparty/tbb @@ -1 +1 @@ -Subproject commit dda6d323f817d05a96f95612d3b158c43cfca241 +Subproject commit efa9881db0d47930f1e713daabc6ac5689efe96c diff --git a/Makefile.user b/Makefile.user index 56127727..c648bc7b 100644 --- a/Makefile.user +++ b/Makefile.user @@ -1,4 +1,4 @@ -CPPFLAGS+= -DMLOG_APP=FilterAny +CPPFLAGS+= -DMLOG_APP=FilterInfo CPPFLAGS+= -DMLOG_ASYNC=FilterError CPPFLAGS+= -DMLOG_BOOT=FilterError CPPFLAGS+= -DMLOG_CPU=FilterError diff --git a/kernel/app/init-example/app/init.cc b/kernel/app/init-example/app/init.cc index 75ad4acc..54228e1e 100644 --- a/kernel/app/init-example/app/init.cc +++ b/kernel/app/init-example/app/init.cc @@ -387,10 +387,7 @@ void test_InterruptControl() { } long SerialFib( long n ) { - if( n<2 ) - return n; - else - return SerialFib(n-1)+SerialFib(n-2); + return n<2 ? n :SerialFib(n-1)+SerialFib(n-2); } class FibTask: public tbb::task { @@ -430,34 +427,10 @@ long ParallelFib( long n ) { void test_TBB(){ MLOG_INFO(mlog::app, "Test TBB"); - class say_hello - { - int id; - public: - say_hello(int i) : id(i) { } - void operator( ) ( ) const - { - printf("hello from task %d\n",id); - } - }; - - - MLOG_INFO(mlog::app, "fib", DVAR(ParallelFib(20))); - - //tbb::task_group tg; - //printf("created task group\n"); - //for(int i=0; i<10; i++){ - //tg.run(say_hello(i)); // spawn 1st task and return - //} - //tg.wait( ); // wait for tasks to complete - //tbb::parallel_for( tbb::blocked_range(0,3), - //[&](tbb::blocked_range r) - //{ - //for (int i=r.begin(); i* r, CapEntry* sce) + { + MLOG_INFO(mlog::ec, "setScheduler", DVAR(this), DVAR(sce)); + ASSERT(r); + + monitor.request(t,[=](Tasklet*){ + if(currentPlace.load() != nullptr){ + r->response(t, optional(false)); + }else{ + TypedCap obj(sce); + if (!obj){ + MLOG_ERROR(mlog::ec, "invalid SC cap entry", DVAR(this), DVAR(sce)); + r->response(t, optional()); + } + auto ret = (_sched.set(this, sce, obj.cap())); + r->response(t, ret); + } + monitor.responseAndRequestDone(); + }); + } + optional ExecutionContext::setSchedulingContext( Tasklet* t, IInvocation* msg, optional sce) { @@ -405,6 +427,8 @@ namespace mythos { case SYSCALL_EXIT: MLOG_INFO(mlog::syscall, "exit"); setFlags(IS_TRAPPED); + unsetSchedulingContext(); + saveState(); break; case SYSCALL_POLL: diff --git a/kernel/objects/execution-context/objects/ExecutionContext.hh b/kernel/objects/execution-context/objects/ExecutionContext.hh index e9f7af80..b0253e2e 100644 --- a/kernel/objects/execution-context/objects/ExecutionContext.hh +++ b/kernel/objects/execution-context/objects/ExecutionContext.hh @@ -78,6 +78,8 @@ namespace mythos { /// only for initial setup optional setSchedulingContext(optional sce); + // for ThreadTeam + void setSchedulingContext(Tasklet* t, IResult* r, CapEntry* sce); optional setSchedulingContext(Tasklet* t, IInvocation* msg, optional sce); Error unsetSchedulingContext(); diff --git a/kernel/objects/processor-allocator/objects/ProcessorAllocator.cc b/kernel/objects/processor-allocator/objects/ProcessorAllocator.cc index 7eee27f2..e4e3e07f 100644 --- a/kernel/objects/processor-allocator/objects/ProcessorAllocator.cc +++ b/kernel/objects/processor-allocator/objects/ProcessorAllocator.cc @@ -56,7 +56,7 @@ namespace mythos { } optional ProcessorAllocator::alloc(){ - MLOG_WARN(mlog::pm, "alloc not synchronized yet"); + MLOG_DETAIL(mlog::pm, __func__); optional ret; if(nFree > 0){ nFree--; @@ -66,6 +66,7 @@ namespace mythos { } void ProcessorAllocator::free(cpu::ThreadID id) { + MLOG_INFO(mlog::pm, __func__, DVAR(id)); freeList[nFree] = id; nFree++; } diff --git a/kernel/objects/processor-allocator/objects/ProcessorAllocator.hh b/kernel/objects/processor-allocator/objects/ProcessorAllocator.hh index dccff36c..1f657b80 100644 --- a/kernel/objects/processor-allocator/objects/ProcessorAllocator.hh +++ b/kernel/objects/processor-allocator/objects/ProcessorAllocator.hh @@ -52,10 +52,24 @@ class ProcessorAllocator void init(); - //todo: synchronize optional alloc(); void free(cpu::ThreadID id); + void alloc(Tasklet* t, IResult* r){ + monitor.request(t,[=](Tasklet*){ + ASSERT(r); + r->response(t, alloc()); + monitor.responseAndRequestDone(); + }); + } + + void free(Tasklet* t, cpu::ThreadID id){ + monitor.request(t,[=](Tasklet*){ + free(id); + monitor.responseAndRequestDone(); + }); + } + CapEntry* getSC(cpu::ThreadID id){ ASSERT(id < cpu::getNumThreads()); return &sc[id]; diff --git a/kernel/objects/scheduling-context/objects/SchedulingContext.hh b/kernel/objects/scheduling-context/objects/SchedulingContext.hh index a713c38b..2f30faae 100644 --- a/kernel/objects/scheduling-context/objects/SchedulingContext.hh +++ b/kernel/objects/scheduling-context/objects/SchedulingContext.hh @@ -94,10 +94,14 @@ namespace mythos { void unbind(handle_t* ec_handle) override; void ready(handle_t* ec_handle) override; + //todo: use capref public: //ThreadTeam void registerThreadTeam(INotifyIdle* tt){ myTeam.store(tt); }; + void resetThreadTeam(){ + myTeam.store(nullptr); + } public: // IKernelObject interface optional deleteCap(CapEntry&, Cap, IDeleter&) override { RETURN(Error::SUCCESS); } diff --git a/kernel/objects/thread-team/mythos/protocol/ThreadTeam.hh b/kernel/objects/thread-team/mythos/protocol/ThreadTeam.hh index 6d623c55..2b70e39e 100644 --- a/kernel/objects/thread-team/mythos/protocol/ThreadTeam.hh +++ b/kernel/objects/thread-team/mythos/protocol/ThreadTeam.hh @@ -45,6 +45,7 @@ namespace mythos { RETRUNNEXTTOEC }; + //needs to be equal to pthread_alloc_type_t in pthread.h of musl enum TeamAllocType{ FAIL = 0, FORCE = 1, @@ -80,10 +81,10 @@ namespace mythos { constexpr static uint16_t label = (proto<<8) + RETTRYRUNEC; enum response{ - FAILED, - ALLOCATED, - DEMANDED, - FORCED + FAILED = 0, + ALLOCATED = 1, + DEMANDED = 2, + FORCED = 3 }; RetTryRunEC() diff --git a/kernel/objects/thread-team/objects/ThreadTeam.cc b/kernel/objects/thread-team/objects/ThreadTeam.cc index 66146426..2e870b53 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.cc +++ b/kernel/objects/thread-team/objects/ThreadTeam.cc @@ -31,21 +31,53 @@ namespace mythos { /* IKernelObject */ - optional ThreadTeam::deleteCap(CapEntry&, Cap, IDeleter&) + optional ThreadTeam::deleteCap(CapEntry&, Cap self, IDeleter& del) { MLOG_DETAIL(mlog::pm, __func__); + ASSERT(state == IDLE); + if (self.isOriginal()) { // the object gets deleted, not a capability reference + ASSERT(pa); + + // free used SCs + auto used = popUsed(); + while(used){ + auto sce = pa->getSC(*used); + TypedCap sc(sce->cap()); + sc->resetThreadTeam(); + //todo: synchronize!!!! + pa->free(*used); + used = popUsed(); + } + + // free unused SCs + auto free = popFree(); + while(free){ + auto sce = pa->getSC(*free); + TypedCap sc(sce->cap()); + sc->resetThreadTeam(); + //todo:: synchronize!!! + pa->free(*free); + free = popFree(); + } + del.deleteObject(del_handle); + } RETURN(Error::SUCCESS); } - void ThreadTeam::deleteObject(Tasklet*, IResult*) + void ThreadTeam::deleteObject(Tasklet* t, IResult* r) { MLOG_DETAIL(mlog::pm, __func__); + ASSERT(state == IDLE); + monitor.doDelete(t, [=](Tasklet* t) { this->memory->free(t, r, this, sizeof(ThreadTeam)); }); } void ThreadTeam::invoke(Tasklet* t, Cap self, IInvocation* msg) { MLOG_DETAIL(mlog::pm, __func__, DVAR(t), DVAR(msg)); monitor.request(t, [=](Tasklet* t){ + ASSERT(state == IDLE); + state = INVOCATION; + tmp_msg = msg; Error err = Error::NOT_IMPLEMENTED; switch (msg->getProtocol()) { case protocol::ThreadTeam::proto: @@ -53,15 +85,110 @@ namespace mythos { break; } if (err != Error::INHIBIT) { + ASSERT(state == INVOCATION); + state = IDLE; + tmp_msg = nullptr; msg->replyResponse(err); monitor.requestDone(); } } ); } +/* IResult */ + void ThreadTeam::response(Tasklet* t, optional id){ + MLOG_DETAIL(mlog::pm, __PRETTY_FUNCTION__); + ASSERT(pa); + ASSERT(tmp_msg); + ASSERT(tmp_msg->getMethod() == protocol::ThreadTeam::TRYRUNEC); + + auto data = tmp_msg->getMessage()->read(); + auto ece = tmp_msg->lookupEntry(data.ec()); + auto ret = tmp_msg->getMessage()->cast(); + + ret->setResponse(protocol::ThreadTeam::RetTryRunEC::FAILED); + + ASSERT(ece); + + if(id){ + MLOG_DETAIL(mlog::pm, DVAR(*id)); + ret->setResponse(protocol::ThreadTeam::RetTryRunEC::DEMANDED); + TypedCap ec(ece); + ASSERT(ec); + tryRunAt(t, *ec, *id); + return; + } + + MLOG_DETAIL(mlog::pm, "SC allocation failed"); + + if(data.allocType == protocol::ThreadTeam::DEMAND){ + if(enqueueDemand(*ece)){ + MLOG_DETAIL(mlog::pm, "enqueued to demand list"); + ret->setResponse(protocol::ThreadTeam::RetTryRunEC::ALLOCATED); + } + }else if(data.allocType == protocol::ThreadTeam::FORCE){ + if(nUsed > 0){ + MLOG_DETAIL(mlog::pm, "force run"); + //todo: use a more sophisticated mapping scheme + ret->setResponse(protocol::ThreadTeam::RetTryRunEC::FORCED); + TypedCap ec(ece); + ASSERT(ec); + tryRunAt(t, *ec, usedList[0]); + return; + } + } + + state = IDLE; + tmp_msg->replyResponse(Error::SUCCESS); + monitor.responseAndRequestDone(); + + } + + void ThreadTeam::response(Tasklet* /*t*/, optional bound){ + MLOG_DETAIL(mlog::pm, __PRETTY_FUNCTION__); + ASSERT(tmp_id != INV_ID); + + if(state == INVOCATION){ + ASSERT(tmp_msg); + ASSERT(tmp_msg->getMethod() == protocol::ThreadTeam::TRYRUNEC); + + auto ret = tmp_msg->getMessage()->cast(); + + if(bound){ + MLOG_DETAIL(mlog::pm, "EC successfully bound to SC"); + pushUsed(tmp_id); + //allready set! ret->setResponse(protocol::ThreadTeam::RetTryRunEC::ALLOCATED); + tmp_msg->replyResponse(Error::SUCCESS); + }else{ + MLOG_ERROR(mlog::pm, "ERROR: failed to bind EC to SC!"); + //todo: reuse sc? + ret->setResponse(protocol::ThreadTeam::RetTryRunEC::FAILED); + tmp_msg->replyResponse(Error::GENERIC_ERROR); + } + }else if(state == SC_NOTIFY){ + if(bound){ + // remove ec from demand queue + removeDemand(tmp_ec); + }else{ + removeUsed(tmp_id); + pushFree(tmp_id); + } + }else{ + MLOG_ERROR(mlog::pm, "ERROR: Invalid operational state"); + } + + state = IDLE; + tmp_id = INV_ID; + monitor.responseAndRequestDone(); + } + /* ThreadTeam */ ThreadTeam::ThreadTeam(IAsyncFree* memory) : memory(memory) + , tmp_msg(nullptr) + , tmp_id(INV_ID) + , tmp_ec(nullptr) + , state(IDLE) + , pa(nullptr) , nFree(0) , nUsed(0) , nDemand(0) @@ -72,90 +199,93 @@ namespace mythos { } bool ThreadTeam::tryRun(ExecutionContext* ec){ - MLOG_DETAIL(mlog::pm, __func__); - auto pal = pa.get(); - ASSERT(pal); + ASSERT(state == IDLE); + ASSERT(pa); + ASSERT(ec); auto id = popFree(); - if(id){ - MLOG_DETAIL(mlog::pm, "take SC from Team ", DVAR(*id)); - }else{ - MLOG_DETAIL(mlog::pm, "try alloc SC from PA"); - id = pal->alloc(); + if(!id){ + id = pa->alloc(); } - if(id && tryRunAt(ec, *id)){ - pushUsed(*id); - return true; - }else{ - MLOG_WARN(mlog::pm, "Cannot allocate SC for EC"); + + if(id){ + if(ec->setSchedulingContext(pa->getSC(*id))){ + pushUsed(*id); + return true; + }else{ + pushFree(*id); + } } return false; } - bool ThreadTeam::tryRunAt(ExecutionContext* ec, cpu::ThreadID id){ - MLOG_DETAIL(mlog::pm, __func__); - auto pal = pa.get(); - ASSERT(pal); - - auto sce = pal->getSC(id); - TypedCap sc(sce->cap()); - sc->registerThreadTeam(static_cast(this)); - auto ret = ec->setSchedulingContext(sce); - if(ret){ - MLOG_DETAIL(mlog::pm, "Init EC bind SC", DVAR(id)); - return true; + void ThreadTeam::bind(optional paPtr) { + MLOG_DETAIL(mlog::pm, "bind processor allocator"); + //todo:: synchronize + if(paPtr){ + pa = *paPtr; }else{ - MLOG_ERROR(mlog::pm, "ERROR: Init EC bind SC failed ", DVAR(id)); + MLOG_ERROR(mlog::pm, "ERROR: binding processor allocator failed"); + pa = nullptr; } - return false; } - Error ThreadTeam::invokeTryRunEC(Tasklet* /*t*/, Cap, IInvocation* msg){ - MLOG_ERROR(mlog::pm, __func__); + void ThreadTeam::unbind(optional ) { + MLOG_ERROR(mlog::pm, "ERROR: unbind processor allocator"); + //todo:: synchronize + pa = nullptr; + } + + void ThreadTeam::tryRunAt(Tasklet* t, ExecutionContext* ec, cpu::ThreadID id){ + MLOG_DETAIL(mlog::pm, __func__, DVARhex(ec), DVAR(id)); + ASSERT(pa); + ASSERT(tmp_id == INV_ID); + tmp_id = id; + auto sce = pa->getSC(id); + ec->setSchedulingContext(t, this, sce); + } + + Error ThreadTeam::invokeTryRunEC(Tasklet* t, Cap, IInvocation* msg){ + MLOG_DETAIL(mlog::pm, __func__); + ASSERT(state == INVOCATION); auto data = msg->getMessage()->read(); auto ece = msg->lookupEntry(data.ec()); auto ret = msg->getMessage()->cast(); + if(!ece){ MLOG_ERROR(mlog::pm, "Error: Did not find EC!"); + ret->setResponse(protocol::ThreadTeam::RetTryRunEC::FAILED); return Error::INVALID_CAPABILITY; } + + auto id = popFree(); - TypedCap ec(ece); - - if(ec && tryRun(*ec)){ - ret->setResponse(protocol::ThreadTeam::RetTryRunEC::ALLOCATED); - return Error::SUCCESS; - } - - if(data.allocType == protocol::ThreadTeam::DEMAND){ - if(enqueueDemand(*ece)){ - ret->setResponse(protocol::ThreadTeam::RetTryRunEC::DEMANDED); - return Error::SUCCESS; - } - }else if(data.allocType == protocol::ThreadTeam::FORCE){ - if(nUsed > 0){ - //todo: use a more sophisticated mapping scheme - auto pal = pa.get(); - ASSERT(pal); - auto sce = pal->getSC(usedList[0]); - auto r = ec->setSchedulingContext(sce); - if(r){ - ret->setResponse(protocol::ThreadTeam::RetTryRunEC::FORCED); - return Error::SUCCESS; - } - } + if(id){ + MLOG_DETAIL(mlog::pm, "take SC from Team ", DVAR(*id)); + ret->setResponse(protocol::ThreadTeam::RetTryRunEC::DEMANDED); + TypedCap ec(ece); + ASSERT(ec); + tryRunAt(t, *ec, *id); + }else{ + MLOG_DETAIL(mlog::pm, "try alloc SC from PA"); + ASSERT(pa); + pa->alloc(t, this); } - - ret->setResponse(protocol::ThreadTeam::RetTryRunEC::FAILED); - return Error::SUCCESS; + + return Error::INHIBIT; } - + Error ThreadTeam::invokeRevokeDemand(Tasklet* /*t*/, Cap, IInvocation* msg){ MLOG_DETAIL(mlog::pm, __func__); + ASSERT(state == INVOCATION); + auto data = msg->getMessage()->read(); auto ece = msg->lookupEntry(data.ec()); auto ret = msg->getMessage()->cast(); + + ret->revoked = false; + if(!ece){ MLOG_ERROR(mlog::pm, "Error: Did not find EC!"); return Error::INVALID_CAPABILITY; @@ -165,24 +295,11 @@ namespace mythos { if(ec && removeDemand(*ec)){ ret->revoked = true; }else{ - MLOG_WARN(mlog::pm, "revoke demand failed"); - ret->revoked = false; + MLOG_INFO(mlog::pm, "revoke demand failed"); } - return Error::SUCCESS; } - void ThreadTeam::notifyIdle(Tasklet* t, cpu::ThreadID id) { - MLOG_DETAIL(mlog::pm, __func__, DVAR(id)); - monitor.request(t, [=](Tasklet*){ - if(!tryRunDemandAt(id)) { - removeUsed(id); - pushFree(id); - } - monitor.responseAndRequestDone(); - }); - } - Error ThreadTeam::invokeRunNextToEC(Tasklet* /*t*/, Cap, IInvocation* /*msg*/){ MLOG_ERROR(mlog::pm, __func__, " NYI!"); return Error::NOT_IMPLEMENTED; @@ -210,6 +327,16 @@ namespace mythos { nUsed++; } + optional ThreadTeam::popUsed(){ + MLOG_DETAIL(mlog::pm, __func__); + optional ret; + if(nUsed > 0){ + nUsed--; + ret = usedList[nUsed]; + } + return ret; + } + void ThreadTeam::removeUsed(cpu::ThreadID id){ MLOG_DETAIL(mlog::pm, __func__, DVAR(id)); for(unsigned i = 0; i < nUsed; i++){ @@ -225,21 +352,24 @@ namespace mythos { } bool ThreadTeam::enqueueDemand(CapEntry* ec){ + MLOG_DETAIL(mlog::pm, __func__); + ASSERT(state == INVOCATION); if(nDemand < MYTHOS_MAX_THREADS){ demandEC[demandList[nDemand]].set(this, ec, ec->cap()); nDemand++; + //dumpDemand(); return true; } return false; } bool ThreadTeam::removeDemand(ExecutionContext* ec){ + MLOG_DETAIL(mlog::pm, __func__, DVARhex(ec)); //find entry for(unsigned i = 0; i < nDemand; i++){ auto di = demandList[i]; auto d = demandEC[di].get(); if(d && *d == ec){ - demandEC[di].reset(); nDemand--; //move following entries for(; i < nDemand; i++){ @@ -247,59 +377,81 @@ namespace mythos { } //move demand index behind used indexes demandList[nDemand] = di; + //reset entry + tmp_ec = *d; + demandEC[di].reset(); + //dumpDemand(); return true; } } - MLOG_WARN(mlog::pm, "did not find EC in demand list "); + MLOG_INFO(mlog::pm, "did not find EC in demand list "); + //dumpDemand(); return false; } - //bool ThreadTeam::tryRunDemand() { - //// demand available? - //if(nDemand){ - ////take first - //auto di = demandList[0]; - //TypedCap ec(demandEC[di]); - //ASSERT(ec); - ////try to run ec - //if(tryRun(*ec)){ - ////reset CapRef - //demandEC[di].reset(); - //// remove from queue - //nDemand--; - //for(unsigned i = 0; i < nDemand; i++){ - //demandList[i] = demandList[i+1]; - //} - //demandList[nDemand] = di; - //return true; - //} - //} - //return false; - //} - - bool ThreadTeam::tryRunDemandAt(cpu::ThreadID id) { + void ThreadTeam::notifyIdle(Tasklet* t, cpu::ThreadID id) { + MLOG_DETAIL(mlog::pm, __func__, DVAR(id)); + monitor.request(t, [=](Tasklet*){ + ASSERT(state == IDLE); + ASSERT(tmp_id == INV_ID); + state = SC_NOTIFY; + + if(!tryRunDemandAt(t, id)) { + removeUsed(id); + pushFree(id); + state = IDLE; + monitor.responseAndRequestDone(); + } + }); + } + + bool ThreadTeam::tryRunDemandAt(Tasklet* t, cpu::ThreadID id) { + MLOG_DETAIL(mlog::pm, __func__); + ASSERT(state == SC_NOTIFY); // demand available? if(nDemand){ //take first auto di = demandList[0]; TypedCap ec(demandEC[di]); ASSERT(ec); + MLOG_DETAIL(mlog::pm, DVARhex(*ec), DVAR(id)); //try to run ec - if(tryRunAt(*ec, id)){ - //reset CapRef - demandEC[di].reset(); - // remove from queue - nDemand--; - for(unsigned i = 0; i < nDemand; i++){ - demandList[i] = demandList[i+1]; - } - demandList[nDemand] = di; - return true; - } + tryRunAt(t, *ec, id); + return true; } + //dumpDemand(); return false; } + void ThreadTeam::bind(optional /*ec*/){} + + void ThreadTeam::unbind(optional ec){ + MLOG_DETAIL(mlog::pm, __func__, DVARhex(ec)); + MLOG_WARN(mlog::pm, "Todo: Not synchronized! -> Handle EC deleted!"); + ASSERT(state == INVOCATION || state == SC_NOTIFY); + if(ec){ + if(*ec == tmp_ec){ + tmp_ec = nullptr; + }else{ + removeDemand(*ec); + } + } + } + + void ThreadTeam::dumpDemand(){ + MLOG_DETAIL(mlog::pm, "demand list:"); + for(unsigned i = 0; i < MYTHOS_MAX_THREADS; i++){ + auto di = demandList[i]; + if(i < nDemand){ + auto d = demandEC[di].get(); + ASSERT(d); + MLOG_DETAIL(mlog::pm, DVAR(i), DVAR(di), DVARhex(*d)); + }else{ + if(i != di) MLOG_DETAIL(mlog::pm, DVAR(i), DVAR(di)," slot free"); + } + } + } + optional ThreadTeamFactory::factory(CapEntry* dstEntry, CapEntry* memEntry, Cap memCap, IAllocator* mem, CapEntry* pae){ auto obj = mem->create(); @@ -309,7 +461,7 @@ namespace mythos { } TypedCap pa(pae); if (!pa) RETHROW(pa); - obj->pa.set(*obj, pae, pa.cap()); + obj->paRef.set(*obj, pae, pa.cap()); Cap cap(*obj); auto res = cap::inherit(*memEntry, memCap, *dstEntry, cap); if (!res) { diff --git a/kernel/objects/thread-team/objects/ThreadTeam.hh b/kernel/objects/thread-team/objects/ThreadTeam.hh index ca6a9de7..5093e612 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.hh +++ b/kernel/objects/thread-team/objects/ThreadTeam.hh @@ -26,6 +26,7 @@ #pragma once #include "async/NestedMonitorDelegating.hh" +#include "async/IResult.hh" #include "objects/IFactory.hh" #include "objects/IKernelObject.hh" #include "cpu/hwthreadid.hh" @@ -41,6 +42,8 @@ namespace mythos { class ThreadTeam : public IKernelObject , public INotifyIdle + , public IResult + , public IResult { public: ThreadTeam(IAsyncFree* memory); @@ -54,47 +57,63 @@ namespace mythos { THROW(Error::TYPE_MISMATCH); } + /* IResult */ + //called from ProcessorAllocator::alloc + void response(Tasklet* t, optional id); + //called from ExecutionContext::setSchedulingContext + void response(Tasklet* t, optional bound); + + // only for init EC bool tryRun(ExecutionContext* ec); - bool tryRunAt(ExecutionContext* ec, cpu::ThreadID id); + + // invocations Error invokeTryRunEC(Tasklet* t, Cap, IInvocation* msg); Error invokeRevokeDemand(Tasklet* t, Cap, IInvocation* msg); Error invokeRunNextToEC(Tasklet* t, Cap, IInvocation* msg); - void bind(optional ) { - MLOG_DETAIL(mlog::pm, "bind processor allocator"); - } + void bind(optional paPtr); + void unbind(optional ); - void unbind(optional ) { - MLOG_ERROR(mlog::pm, "ERROR: unbind processor allocator"); - } - - void bind(optional /*ec*/){} - - void unbind(optional ec){ - MLOG_DETAIL(mlog::pm, __func__); - if(ec){ - removeDemand(*ec); - } - } + void bind(optional /*ec*/); + void unbind(optional ec); void notifyIdle(Tasklet* t, cpu::ThreadID id) override; private: + void tryRunAt(Tasklet* t, ExecutionContext* ec, cpu::ThreadID id); + void pushFree(cpu::ThreadID id); optional popFree(); + void pushUsed(cpu::ThreadID id); void removeUsed(cpu::ThreadID id); + optional popUsed(); + bool enqueueDemand(CapEntry* ec); bool removeDemand(ExecutionContext* ec); - //bool tryRunDemand(); - bool tryRunDemandAt(cpu::ThreadID id); + bool tryRunDemandAt(Tasklet* t, cpu::ThreadID id); + void dumpDemand(); private: + LinkedList::Queueable del_handle = {this}; IAsyncFree* memory; async::NestedMonitorDelegating monitor; + /* state for async operation handling */ + IInvocation* tmp_msg; + static constexpr cpu::ThreadID INV_ID = cpu::ThreadID(-1); + cpu::ThreadID tmp_id; + ExecutionContext* tmp_ec; + enum OperationalState{ + IDLE, + INVOCATION, + SC_NOTIFY + }; + OperationalState state; + friend class ThreadTeamFactory; - CapRef pa; + CapRef paRef; + ProcessorAllocator* pa; cpu::ThreadID freeList[MYTHOS_MAX_THREADS]; unsigned nFree; cpu::ThreadID usedList[MYTHOS_MAX_THREADS]; diff --git a/kernel/runtime/cxx/runtime/cxxsupport.cc b/kernel/runtime/cxx/runtime/cxxsupport.cc index 2b477edd..b02e0767 100644 --- a/kernel/runtime/cxx/runtime/cxxsupport.cc +++ b/kernel/runtime/cxx/runtime/cxxsupport.cc @@ -54,6 +54,8 @@ #include "runtime/umem.hh" #include "runtime/thread-extra.hh" #include "runtime/ThreadTeam.hh" +#include "runtime/Mutex.hh" +#include "util/optional.hh" #include "mythos/InfoFrame.hh" extern mythos::InfoFrame* info_ptr asm("info_ptr"); @@ -76,6 +78,54 @@ void setRemotePortalPtr(uintptr_t targetTLS, mythos::CapPtr p){ *ptr = p; } +mythos::CapPtr getRemotePortalPtr(pthread_t t){ + auto rp = reinterpret_cast(t - (pthread_self() - reinterpret_cast(&localPortalPtr))); + return *rp; +} + +template +class ThreadPool{ + public: + ThreadPool() + : top(0) + {} + + struct ThreadPoolEntry{ + mythos::CapPtr ec; + mythos::CapPtr portal; + }; + + void push(mythos::CapPtr ec, mythos::CapPtr portal){ + mythos::Mutex::Lock guard(mutex); + if(top < SIZE){ + pool[top] = {ec, portal}; + top++; + MLOG_DETAIL(mlog::app, "pushed to thread pool", DVAR(ec), DVAR(portal)); + }else{ + MLOG_WARN(mlog::app, "Thread pool full!"); + } + } + + mythos::optional pop(){ + mythos::Mutex::Lock guard(mutex); + if(top){ + top--; + auto ec = pool[top].ec; + auto portal = pool[top].portal; + MLOG_DETAIL(mlog::app, "pop from thread pool", DVAR(ec), DVAR(portal)); + return pool[top]; + } + MLOG_DETAIL(mlog::app, "thread pool empty"); + return mythos::optional(); + } + + private: + mythos::Mutex mutex; + ThreadPoolEntry pool[SIZE]; + unsigned top; +}; + +ThreadPool<1024> threadPool; // synchronization for pthread deletion (exit/join) struct PthreadCleaner{ @@ -133,6 +183,18 @@ extern "C" [[noreturn]] void __assert_fail (const char *expr, const char *file, } void mythosExit(){ + //todo: ASSERT(myEC == init::EC) + + //todo: free capspace, all ECs, + mythos::PortalLock pl(localPortal); + MLOG_ERROR(mlog::app, "Free all dynamically allocated Caps"); + capAlloc.freeAll(pl); + MLOG_ERROR(mlog::app, "Free Thread Team"); + myCS.deleteCap(pl, mythos::init::THREAD_TEAM).wait(); + //MLOG_ERROR(mlog::app, "Free init EC"); + //myCS.deleteCap(pl, mythos::init::EC).wait(); + //myCS.deleteCap(pl, mythos::init::CSPACE).wait(); + //should never return MLOG_ERROR(mlog::app, "MYTHOS:PLEASE KILL ME!!!!!!1 elf"); } @@ -164,7 +226,7 @@ int prlimit( int my_sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask) { //MLOG_DETAIL(mlog::app, "syscall sched_setaffinity", DVAR(pid), DVAR(cpusetsize), DVARhex(mask)); - if(cpusetsize == 8/*info_ptr->getNumThreads()*/ && mask == NULL) return -EFAULT; + if(cpusetsize == info_ptr->getNumThreads() && mask == NULL) return -EFAULT; return 0; } @@ -174,9 +236,9 @@ int my_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask) if (mask) { //CPU_ZERO(mask); memset(mask, 0, cpusetsize); - for(int i = 0; i < 8/*info_ptr->getNumThreads()*/; i++) CPU_SET(i, mask); + for(int i = 0; i < info_ptr->getNumThreads(); i++) CPU_SET(i, mask); } - return 8/*info_ptr->getNumThreads()*/; + return info_ptr->getNumThreads(); } void clock_gettime(long clk, struct timespec *ts){ @@ -234,7 +296,7 @@ extern "C" long mythos_musl_syscall( MLOG_WARN(mlog::app, "syscall getpid NYI"); return mythos_get_pthread_ec_self(); case 60: // exit(exit_code) - //MLOG_ERROR(mlog::app, "syscall exit", DVAR(a1)); + MLOG_DETAIL(mlog::app, "syscall exit", DVAR(a1)); pthreadCleaner.exit(); asm volatile ("syscall" : : "D"(0), "S"(a1) : "memory"); return 0; @@ -307,9 +369,11 @@ extern "C" int munmap(void *start, size_t len) extern "C" int unmapself(void *start, size_t len) { // see pthread_exit: another pthread might reuse the memory before unmapped thread exited - MLOG_WARN(mlog::app, "unmapself: possible race condition! "); - MLOG_WARN(mlog::app, "unmapself: who's gonna free the EC and SC?! "); + MLOG_WARN(mlog::app, "unmapself"); + //todo: race condition? mythos::heap.free(reinterpret_cast(start)); + threadPool.push(mythos_get_pthread_ec_self(), localPortalPtr); + asm volatile ("syscall" : : "D"(0), "S"(0) : "memory"); return 0; } @@ -325,10 +389,10 @@ extern "C" int mprotect(void *addr, size_t len, int prot) int myclone( int (*func)(void *), void *stack, int flags, - void *arg, int* ptid, void* tls, int* ctid) + void *arg, int* ptid, void* tls, int* ctid, + int allocType) { - MLOG_DETAIL(mlog::app, "myclone"); - setRemotePortalPtr(reinterpret_cast(tls), 42); + MLOG_DETAIL(mlog::app, "myclone", DVAR(allocType)); ASSERT(tls != nullptr); // The compiler expect a kinda strange alignment coming from clone: // -> rsp % 16 must be 8 @@ -336,33 +400,56 @@ int myclone( // We will use the same trick for alignment as musl libc auto rsp = (uintptr_t(stack) & uintptr_t(-16))-8; - mythos::PortalLock pl(localPortal); // future access will fail if the portal is in use already - mythos::ExecutionContext ec(capAlloc()); - if (ptid && (flags&CLONE_PARENT_SETTID)) *ptid = int(ec.cap()); + mythos::CapPtr ecPtr; + mythos::CapPtr portalPtr; + + auto tpe = threadPool.pop(); + if(tpe){ + ecPtr = tpe->ec; + portalPtr = tpe->portal; + }else{ + ecPtr = capAlloc(); + portalPtr = capAlloc(); + } + + mythos::PortalLock pl(localPortal); + mythos::ExecutionContext ec(ecPtr); + + if (ptid && (flags&CLONE_PARENT_SETTID)) *ptid = int(ecPtr); // @todo store thread-specific ctid pointer, which should set to 0 by the OS on the thread's exit - auto res = ec.create(kmem) - .as(myAS) - .cs(myCS) - .rawStack(rsp) - .rawFun(func, arg) - .suspended(false) - .fs(tls) - .invokeVia(pl) - .wait(); - - // create Portal - ASSERT(ec.cap() < mythos::MAX_IB); - mythos::CapPtr pPtr = capAlloc(); - mythos::Portal newPortal(pPtr, info_ptr->getInvocationBuf(pPtr)); - newPortal.create(pl, kmem).wait(); - newPortal.bind(pl, infoFrame, info_ptr->getIbOffset(pPtr), ec.cap()); - setRemotePortalPtr(reinterpret_cast(tls), pPtr); - MLOG_WARN(mlog::app, "todo: free Portal!"); - - auto tres = team.tryRunEC(pl, ec).wait(); - if(tres){ - return ec.cap(); + if(tpe){ + // Reuse EC -> configure regs + mythos::ExecutionContext::register_t regs; + regs.rsp = uintptr_t(rsp), // stack + regs.rip = uintptr_t(func); // start function; + regs.rdi = uintptr_t(arg); // user context + regs.fs_base = uintptr_t(tls); // thread local storage + auto res = ec.writeRegisters(pl, regs, true).wait(); + }else{ + //create new EC + auto res = ec.create(kmem) + .as(myAS) + .cs(myCS) + .rawStack(rsp) + .rawFun(func, arg) + .suspended(false) + .fs(tls) + .invokeVia(pl) + .wait(); + + // create Portal + ASSERT(ec.cap() < mythos::MAX_IB); + mythos::Portal newPortal(portalPtr, info_ptr->getInvocationBuf(portalPtr)); + newPortal.create(pl, kmem).wait(); + newPortal.bind(pl, infoFrame, info_ptr->getIbOffset(portalPtr), ec.cap()); + } + + setRemotePortalPtr(reinterpret_cast(tls), portalPtr); + + auto tres = team.tryRunEC(pl, ec, allocType).wait(); + if(tres && tres->notFailed()){ + return ecPtr; } MLOG_WARN(mlog::app, "Processor allocation failed!"); //todo: set errno = EAGAIN @@ -377,8 +464,9 @@ extern "C" int clone(int (*func)(void *), void *stack, int flags, void *arg, ... int* ptid = va_arg(args, int*); void* tls = va_arg(args, void*); int* ctid = va_arg(args, int*); + int allocType = va_arg(args, int); va_end(args); - return myclone(func, stack, flags, arg, ptid, tls, ctid); + return myclone(func, stack, flags, arg, ptid, tls, ctid, allocType); } // synchronize and cleanup exited pthread @@ -387,12 +475,26 @@ extern "C" void mythos_pthread_cleanup(pthread_t t){ // wait for target pthread to exit pthreadCleaner.wait(t); // delete EC of target pthread - auto cap = mythos_get_pthread_ec(t); - mythos::PortalLock pl(localPortal); - capAlloc.free(cap, pl); + auto ec = mythos_get_pthread_ec(t); + auto portal = getRemotePortalPtr(t); + threadPool.push(ec, portal); // memory of target pthread will be free when returning from this function } +extern "C" int mythos_revoke_demand(pthread_t t){ + MLOG_WARN(mlog::app, "revoke demand"); + mythos::PortalLock pl(localPortal); + auto ecPtr = mythos_get_pthread_ec(t); + mythos::ExecutionContext ec(ecPtr); + auto res = team.revokeDemand(pl, ec).wait(); + if(res){ + auto portalPtr = getRemotePortalPtr(t); + threadPool.push(ecPtr, portalPtr); + MLOG_WARN(mlog::app, "who's gonna free pthreads memory?"); + } + return res && res->revoked ? 0 : (-1); +} + struct dl_phdr_info { void* dlpi_addr; /* Base address of object */ diff --git a/kernel/runtime/kobject/runtime/SimpleCapAlloc.hh b/kernel/runtime/kobject/runtime/SimpleCapAlloc.hh index e5b12ff8..c924f70f 100644 --- a/kernel/runtime/kobject/runtime/SimpleCapAlloc.hh +++ b/kernel/runtime/kobject/runtime/SimpleCapAlloc.hh @@ -86,6 +86,26 @@ namespace mythos { return res; } + void freeAll(PortalLock& pl){ + Mutex::Lock guard(m); + MLOG_DETAIL(mlog::app, __func__); + for(uint32_t i = START; i < next; i++){ + bool isFree = false; + for(uint32_t s = 0; s < top; s++){ + if(caps[s] == i){ + isFree = true; + break; + } + } + + if(!isFree){ + auto res = cs.deleteCap(pl, i).wait(); + } + } + next = START; + top = 0; + } + optional free(KObject p, PortalLock& pl) { return free(p.cap(), pl); } protected: diff --git a/kernel/runtime/kobject/runtime/ThreadTeam.hh b/kernel/runtime/kobject/runtime/ThreadTeam.hh index 5e53bd73..067a58de 100644 --- a/kernel/runtime/kobject/runtime/ThreadTeam.hh +++ b/kernel/runtime/kobject/runtime/ThreadTeam.hh @@ -43,7 +43,22 @@ namespace mythos { return pr.invoke(kmem.cap(), _cap, factory, pa); } - PortalFuture tryRunEC(PortalLock pr, ExecutionContext ec, int at = protocol::ThreadTeam::FAIL){ + struct RunResult{ + RunResult() {} + RunResult(InvocationBuf* ib) { + auto msg = ib->cast(); + response = msg->response; + } + + bool failed() const { return response == protocol::ThreadTeam::RetTryRunEC::FAILED; } + bool allocated() const { return response == protocol::ThreadTeam::RetTryRunEC::ALLOCATED; } + bool notFailed() const { return response == protocol::ThreadTeam::RetTryRunEC::ALLOCATED + || response == protocol::ThreadTeam::RetTryRunEC::DEMANDED + || response == protocol::ThreadTeam::RetTryRunEC::FORCED; } + int response = 0; + }; + + PortalFuture tryRunEC(PortalLock pr, ExecutionContext ec, int at = protocol::ThreadTeam::FAIL){ return pr.invoke(_cap, ec.cap(), at); } @@ -51,7 +66,16 @@ namespace mythos { return pr.invoke(_cap, ec.cap(), ec_place.cap()); } - PortalFuture revokeDemand(PortalLock pr, ExecutionContext ec){ + struct RevokeResult{ + RevokeResult() {} + RevokeResult(InvocationBuf* ib) { + auto msg = ib->cast(); + revoked = msg->revoked; + } + + bool revoked = false; + }; + PortalFuture revokeDemand(PortalLock pr, ExecutionContext ec){ return pr.invoke(_cap, ec.cap()); } }; From 6d9f1e5c33ebe3dbd846a56a589fc5eacff88bad Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Thu, 18 Feb 2021 22:09:03 +0100 Subject: [PATCH 11/42] ThreadTeam --- .../objects/ExecutionContext.hh | 3 ++ .../objects/thread-team/objects/ThreadTeam.cc | 30 +++++++++++++------ .../objects/thread-team/objects/ThreadTeam.hh | 2 +- kernel/runtime/cxx/runtime/cxxsupport.cc | 2 +- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/kernel/objects/execution-context/objects/ExecutionContext.hh b/kernel/objects/execution-context/objects/ExecutionContext.hh index b0253e2e..26d58f19 100644 --- a/kernel/objects/execution-context/objects/ExecutionContext.hh +++ b/kernel/objects/execution-context/objects/ExecutionContext.hh @@ -183,6 +183,9 @@ namespace mythos { LinkedList::Queueable del_handle = {this}; IAsyncFree* memory; + + public: + Tasklet threadTeamTasklet; }; class ExecutionContextFactory : public FactoryBase diff --git a/kernel/objects/thread-team/objects/ThreadTeam.cc b/kernel/objects/thread-team/objects/ThreadTeam.cc index 2e870b53..7974fea3 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.cc +++ b/kernel/objects/thread-team/objects/ThreadTeam.cc @@ -111,6 +111,10 @@ namespace mythos { if(id){ MLOG_DETAIL(mlog::pm, DVAR(*id)); + auto sce = pa->getSC(*id); + TypedCap sc(sce->cap()); + sc->registerThreadTeam(this); + ret->setResponse(protocol::ThreadTeam::RetTryRunEC::DEMANDED); TypedCap ec(ece); ASSERT(ec); @@ -167,7 +171,7 @@ namespace mythos { }else if(state == SC_NOTIFY){ if(bound){ // remove ec from demand queue - removeDemand(tmp_ec); + removeDemand(tmp_ec, true); }else{ removeUsed(tmp_id); pushFree(tmp_id); @@ -292,7 +296,7 @@ namespace mythos { } TypedCap ec(ece); - if(ec && removeDemand(*ec)){ + if(ec && removeDemand(*ec, true)){ ret->revoked = true; }else{ MLOG_INFO(mlog::pm, "revoke demand failed"); @@ -363,8 +367,8 @@ namespace mythos { return false; } - bool ThreadTeam::removeDemand(ExecutionContext* ec){ - MLOG_DETAIL(mlog::pm, __func__, DVARhex(ec)); + bool ThreadTeam::removeDemand(ExecutionContext* ec, bool resetRef){ + MLOG_DETAIL(mlog::pm, __func__, DVARhex(ec), DVAR(resetRef)); //find entry for(unsigned i = 0; i < nDemand; i++){ auto di = demandList[i]; @@ -378,8 +382,10 @@ namespace mythos { //move demand index behind used indexes demandList[nDemand] = di; //reset entry - tmp_ec = *d; - demandEC[di].reset(); + if(resetRef){ + tmp_ec = *d; + demandEC[di].reset(); + } //dumpDemand(); return true; } @@ -427,13 +433,19 @@ namespace mythos { void ThreadTeam::unbind(optional ec){ MLOG_DETAIL(mlog::pm, __func__, DVARhex(ec)); - MLOG_WARN(mlog::pm, "Todo: Not synchronized! -> Handle EC deleted!"); - ASSERT(state == INVOCATION || state == SC_NOTIFY); if(ec){ if(*ec == tmp_ec){ + MLOG_DETAIL(mlog::pm, "synchronous unbind"); tmp_ec = nullptr; }else{ - removeDemand(*ec); + MLOG_DETAIL(mlog::pm, "asynchronous unbind"); + //todo: tasklet valid after unbind? + auto ecPtr = *ec; + monitor.request(&ec->threadTeamTasklet, [=](Tasklet*){ + ASSERT(state == IDLE); + removeDemand(ecPtr, false); + monitor.responseAndRequestDone(); + }); } } } diff --git a/kernel/objects/thread-team/objects/ThreadTeam.hh b/kernel/objects/thread-team/objects/ThreadTeam.hh index 5093e612..b44004f1 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.hh +++ b/kernel/objects/thread-team/objects/ThreadTeam.hh @@ -90,7 +90,7 @@ namespace mythos { optional popUsed(); bool enqueueDemand(CapEntry* ec); - bool removeDemand(ExecutionContext* ec); + bool removeDemand(ExecutionContext* ec, bool resetRef); bool tryRunDemandAt(Tasklet* t, cpu::ThreadID id); void dumpDemand(); diff --git a/kernel/runtime/cxx/runtime/cxxsupport.cc b/kernel/runtime/cxx/runtime/cxxsupport.cc index b02e0767..e4d95f68 100644 --- a/kernel/runtime/cxx/runtime/cxxsupport.cc +++ b/kernel/runtime/cxx/runtime/cxxsupport.cc @@ -327,7 +327,7 @@ extern "C" long mythos_musl_syscall( clock_gettime(a1, reinterpret_cast(a2)); return 0; case 231: // exit_group for all pthreads - MLOG_WARN(mlog::app, "syscall exit_group NYI"); + MLOG_WARN(mlog::app, "syscall exit_group "); mythosExit(); return 0; case 302: // prlimit64 From dd416b6a1ad44f68d0b52acb01c78f92feccdaea Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Thu, 25 Feb 2021 13:27:29 +0100 Subject: [PATCH 12/42] trigger pagemap bug --- kernel/app/init-example/app/init.cc | 51 +++++++++++++++---- .../memory-amd64/objects/PageMapAmd64.cc | 1 + 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/kernel/app/init-example/app/init.cc b/kernel/app/init-example/app/init.cc index e27c8497..1bb8259a 100644 --- a/kernel/app/init-example/app/init.cc +++ b/kernel/app/init-example/app/init.cc @@ -517,26 +517,57 @@ void test_process(){ MLOG_INFO(mlog::app, "Test process finished"); } +void pageMapBug(){ + MLOG_INFO(mlog::app, "Trigger PageMap deadlock"); + + mythos::PortalLock pl(portal); + + mythos::PageMap pm4(capAlloc()); + mythos::PageMap pm3(capAlloc()); + mythos::PageMap pm2(capAlloc()); + + auto res = pm4.create(pl, kmem, 4).wait(); + ASSERT(res); + res = pm3.create(pl, kmem, 3).wait(); + ASSERT(res); + res = pm2.create(pl, kmem, 2).wait(); + ASSERT(res); + + uintptr_t vaddr = 0x4000000; + + pm4.installMap(pl, pm3, ((vaddr >> 39) & 0x1FF) << 39, 4, + mythos::protocol::PageMap::MapFlags().writable(true).configurable(true)).wait(); + pm3.installMap(pl, pm2, ((vaddr >> 30) & 0x1FF) << 30, 3, + mythos::protocol::PageMap::MapFlags().writable(true).configurable(true)).wait(); + + MLOG_INFO(mlog::app, "Try to delete pm3 -> deadlock"); + + capAlloc.free(pm3.cap(), pl); + + MLOG_INFO(mlog::app, "If you can read this, you might have fixed the deadlock?!"); +} + int main() { char const str[] = "Hello world!"; mythos::syscall_debug(str, sizeof(str)-1); MLOG_ERROR(mlog::app, "application is starting :)", DVARhex(info_ptr), DVARhex(initstack_top)); - test_float(); - test_Example(); - test_Portal(); + //test_float(); + //test_Example(); + //test_Portal(); test_heap(); // heap must be initialized for tls test - test_tls(); - test_exceptions(); + //test_tls(); + //test_exceptions(); //test_InterruptControl(); //test_HostChannel(portal, 24*1024*1024, 2*1024*1024); - test_ExecutionContext(); - test_pthreads(); - test_Rapl(); - test_processor_allocator(); - test_process(); + //test_ExecutionContext(); + //test_pthreads(); + //test_Rapl(); + //test_processor_allocator(); + //test_process(); //test_CgaScreen(); + pageMapBug(); char const end[] = "bye, cruel world!"; mythos::syscall_debug(end, sizeof(end)-1); diff --git a/kernel/objects/memory-amd64/objects/PageMapAmd64.cc b/kernel/objects/memory-amd64/objects/PageMapAmd64.cc index a3d88dbb..989a1909 100644 --- a/kernel/objects/memory-amd64/objects/PageMapAmd64.cc +++ b/kernel/objects/memory-amd64/objects/PageMapAmd64.cc @@ -111,6 +111,7 @@ namespace mythos { if (self.isOriginal()) { MLOG_DETAIL(mlog::cap, "delete PageMap", self); for (size_t i = 0; i < num_caps(); ++i) { + if(_cap_table(i).is_locked()) MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, "table is locked and cannot be deleted! -> deadlock!", self); auto res = del.deleteEntry(_cap_table(i)); ASSERT_MSG(res, "Mapped entries must be deletable."); if (!res) RETHROW(res); From 13611a59603543ca43735e61d295dda0e23e97a0 Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Thu, 25 Feb 2021 21:56:14 +0100 Subject: [PATCH 13/42] debug output --- .../capability-spinning/objects/CapEntry.cc | 1 + .../capability-spinning/objects/CapEntry.hh | 20 ++++++++++++++++--- .../objects/RevokeOperation.cc | 4 +++- .../memory-amd64/objects/PageMapAmd64.cc | 7 ++++--- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/kernel/objects/capability-spinning/objects/CapEntry.cc b/kernel/objects/capability-spinning/objects/CapEntry.cc index 52c134ed..7e8f1914 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.cc +++ b/kernel/objects/capability-spinning/objects/CapEntry.cc @@ -139,6 +139,7 @@ namespace mythos { Error CapEntry::try_lock_prev() { auto prev = Link(_prev).ptr(); + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this), DVAR(prev)); if (!prev) { return Error::GENERIC_ERROR; } diff --git a/kernel/objects/capability-spinning/objects/CapEntry.hh b/kernel/objects/capability-spinning/objects/CapEntry.hh index e837ed87..1bf4e9b0 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.hh +++ b/kernel/objects/capability-spinning/objects/CapEntry.hh @@ -84,9 +84,23 @@ namespace mythos { bool kill(); optional unlink(); - bool try_lock() { return !(_next.fetch_or(LOCKED_FLAG) & LOCKED_FLAG); } - void lock() { while (!try_lock()) { hwthread_pause(); } } - void unlock() { auto res = _next.fetch_and(~LOCKED_FLAG); ASSERT(res & LOCKED_FLAG); } + bool try_lock() { + bool ret = !(_next.fetch_or(LOCKED_FLAG) & LOCKED_FLAG); + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this), ret? " locked" : "locking failed!"); + return ret; } + void lock() { + int loop = 0; + while (!try_lock()) { + hwthread_pause(); + loop++; + if(loop > 2){ + MLOG_ERROR(mlog::cap, " lockeing failed too many times -> fail"); + while(1); + } + } } + void unlock() { + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this)); + auto res = _next.fetch_and(~LOCKED_FLAG); ASSERT(res & LOCKED_FLAG); } /// only for assertions and debugging /// only trust the result if it is false and it should be true diff --git a/kernel/objects/capability-spinning/objects/RevokeOperation.cc b/kernel/objects/capability-spinning/objects/RevokeOperation.cc index 18e373ca..bfbaff3d 100644 --- a/kernel/objects/capability-spinning/objects/RevokeOperation.cc +++ b/kernel/objects/capability-spinning/objects/RevokeOperation.cc @@ -110,7 +110,7 @@ namespace mythos { do { if (_startTraversal(root, rootCap)) { leaf = _findLockedLeaf(root); - MLOG_DETAIL(mlog::cap, "_findLockedLeaf returned", DVAR(*leaf), DVAR(rootCap)); + MLOG_ERROR(mlog::cap, "_findLockedLeaf returned", DVAR(*leaf), DVAR(rootCap)); if (leaf == root && !rootCap.isZombie()) { // this is a revoke, do not delete the root. no more children -> we are done root->finishRevoke(); @@ -145,6 +145,7 @@ namespace mythos { bool RevokeOperation::_startTraversal(CapEntry* root, Cap rootCap) { + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__ ); if (!root->lock_prev()) { // start is currently unlinked // must be the work of another deleter ... success! @@ -171,6 +172,7 @@ namespace mythos { CapEntry* RevokeOperation::_findLockedLeaf(CapEntry* root) { + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__ ); auto curEntry = root; while (true) { auto curCap = curEntry->cap(); diff --git a/kernel/objects/memory-amd64/objects/PageMapAmd64.cc b/kernel/objects/memory-amd64/objects/PageMapAmd64.cc index 989a1909..0b19a808 100644 --- a/kernel/objects/memory-amd64/objects/PageMapAmd64.cc +++ b/kernel/objects/memory-amd64/objects/PageMapAmd64.cc @@ -101,17 +101,18 @@ namespace mythos { optional PageMap::MappedPageMap::deleteCap(CapEntry& entry, Cap /*self*/, IDeleter&) { auto idx = &entry - &map->_cap_table(0); - MLOG_DETAIL(mlog::cap, "delete mapped PageMap", DVAR(idx)); + MLOG_ERROR(mlog::cap, "delete mapped PageMap", DVAR(idx)); map->_pm_table(idx).reset(); RETURN(Error::SUCCESS); } optional PageMap::deleteCap(CapEntry&, Cap self, IDeleter& del) { + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, self); if (self.isOriginal()) { - MLOG_DETAIL(mlog::cap, "delete PageMap", self); + MLOG_ERROR(mlog::cap, "delete PageMap", self); for (size_t i = 0; i < num_caps(); ++i) { - if(_cap_table(i).is_locked()) MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, "table is locked and cannot be deleted! -> deadlock!", self); + if(_cap_table(i).is_locked()) MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, "table is locked and cannot be deleted! -> deadlock detected!"); auto res = del.deleteEntry(_cap_table(i)); ASSERT_MSG(res, "Mapped entries must be deletable."); if (!res) RETHROW(res); From 9d43fb7b3b9562bc510efdd48fbee8599eab08c1 Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Fri, 26 Feb 2021 11:20:19 +0100 Subject: [PATCH 14/42] debug output --- kernel/objects/capability-spinning/objects/CapEntry.cc | 2 ++ .../capability-spinning/objects/RevokeOperation.cc | 5 +++-- kernel/objects/memory-amd64/objects/PageMapAmd64.cc | 8 +++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/kernel/objects/capability-spinning/objects/CapEntry.cc b/kernel/objects/capability-spinning/objects/CapEntry.cc index 7e8f1914..ab564c22 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.cc +++ b/kernel/objects/capability-spinning/objects/CapEntry.cc @@ -80,6 +80,7 @@ namespace mythos { optional CapEntry::moveTo(CapEntry& other) { + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this), DVAR(other)); ASSERT(other.cap().isAllocated()); ASSERT(!other.isLinked()); if (!lock_prev()) { @@ -129,6 +130,7 @@ namespace mythos { { auto next = Link(_next).withoutFlags(); auto prev = Link(_prev).withoutFlags(); + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this)); next->_prev.store(prev.value()); prev->_next.store(next.value()); _prev.store(Link().value()); diff --git a/kernel/objects/capability-spinning/objects/RevokeOperation.cc b/kernel/objects/capability-spinning/objects/RevokeOperation.cc index bfbaff3d..3bad991e 100644 --- a/kernel/objects/capability-spinning/objects/RevokeOperation.cc +++ b/kernel/objects/capability-spinning/objects/RevokeOperation.cc @@ -106,6 +106,7 @@ namespace mythos { optional RevokeOperation::_delete(CapEntry* root, Cap rootCap) { + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(root), DVAR(rootCap)); CapEntry* leaf; do { if (_startTraversal(root, rootCap)) { @@ -145,7 +146,7 @@ namespace mythos { bool RevokeOperation::_startTraversal(CapEntry* root, Cap rootCap) { - MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__ ); + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(root), DVAR(rootCap) ); if (!root->lock_prev()) { // start is currently unlinked // must be the work of another deleter ... success! @@ -172,7 +173,7 @@ namespace mythos { CapEntry* RevokeOperation::_findLockedLeaf(CapEntry* root) { - MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__ ); + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(root) ); auto curEntry = root; while (true) { auto curCap = curEntry->cap(); diff --git a/kernel/objects/memory-amd64/objects/PageMapAmd64.cc b/kernel/objects/memory-amd64/objects/PageMapAmd64.cc index 0b19a808..3f54a4a5 100644 --- a/kernel/objects/memory-amd64/objects/PageMapAmd64.cc +++ b/kernel/objects/memory-amd64/objects/PageMapAmd64.cc @@ -90,16 +90,18 @@ namespace mythos { for (size_t i = num_caps(); i < TABLE_SIZE; ++i) MLOG_INFO(mlog::cap, i, _pm_table(i)); } - optional PageMap::MappedFrame::deleteCap(CapEntry& entry, Cap /*self*/, IDeleter&) + optional PageMap::MappedFrame::deleteCap(CapEntry& entry, Cap self, IDeleter&) { + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(entry), DVAR(self), DVARhex(this)); auto idx = &entry - &map->_cap_table(0); MLOG_DETAIL(mlog::cap, "delete mapped Frame", DVAR(idx)); map->_pm_table(idx).reset(); RETURN(Error::SUCCESS); } - optional PageMap::MappedPageMap::deleteCap(CapEntry& entry, Cap /*self*/, IDeleter&) + optional PageMap::MappedPageMap::deleteCap(CapEntry& entry, Cap self, IDeleter&) { + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(entry), DVAR(self), DVARhex(this)); auto idx = &entry - &map->_cap_table(0); MLOG_ERROR(mlog::cap, "delete mapped PageMap", DVAR(idx)); map->_pm_table(idx).reset(); @@ -108,7 +110,7 @@ namespace mythos { optional PageMap::deleteCap(CapEntry&, Cap self, IDeleter& del) { - MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, self); + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, self, DVARhex(this)); if (self.isOriginal()) { MLOG_ERROR(mlog::cap, "delete PageMap", self); for (size_t i = 0; i < num_caps(); ++i) { From 418ba4502ec064cdb4a1683497bf14b64cc9c828 Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Fri, 26 Feb 2021 11:38:13 +0100 Subject: [PATCH 15/42] debug output --- kernel/objects/capability-spinning/objects/CapEntry.cc | 3 +++ kernel/objects/capability-spinning/objects/CapEntry.hh | 1 + 2 files changed, 4 insertions(+) diff --git a/kernel/objects/capability-spinning/objects/CapEntry.cc b/kernel/objects/capability-spinning/objects/CapEntry.cc index ab564c22..db56b64d 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.cc +++ b/kernel/objects/capability-spinning/objects/CapEntry.cc @@ -32,6 +32,7 @@ namespace mythos { void CapEntry::initRoot(Cap c) { + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this)); ASSERT(isKernelAddress(this)); ASSERT(c.isUsable()); ASSERT(cap().isEmpty()); @@ -62,6 +63,7 @@ namespace mythos { void CapEntry::reset() { + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this)); ASSERT(isUnlinked() || cap().isAllocated()); _prev.store(Link().value()); _next.store(Link().value()); @@ -128,6 +130,7 @@ namespace mythos { optional CapEntry::unlink() { + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this)); auto next = Link(_next).withoutFlags(); auto prev = Link(_prev).withoutFlags(); MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this)); diff --git a/kernel/objects/capability-spinning/objects/CapEntry.hh b/kernel/objects/capability-spinning/objects/CapEntry.hh index 1bf4e9b0..c620a2b4 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.hh +++ b/kernel/objects/capability-spinning/objects/CapEntry.hh @@ -199,6 +199,7 @@ namespace mythos { CapEntry& targetEntry, Cap targetCap, COMMITFUN const& commit) { + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this), DVAR(parentCap), DVAR(targetEntry), DVAR(targetCap)); ASSERT(isKernelAddress(this)); ASSERT(targetEntry.cap().isAllocated()); lock(); // lock the parent entry, the child is already acquired From 9d9c9d73686208f09ecab89b9e5a4ce14c67949e Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Fri, 26 Feb 2021 11:46:57 +0100 Subject: [PATCH 16/42] rename CapEntry::unlink --- kernel/objects/capability-spinning/objects/CapEntry.cc | 3 +-- kernel/objects/capability-spinning/objects/CapEntry.hh | 2 +- kernel/objects/capability-spinning/objects/RevokeOperation.cc | 2 +- kernel/objects/capability-utils/objects/ops.hh | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/kernel/objects/capability-spinning/objects/CapEntry.cc b/kernel/objects/capability-spinning/objects/CapEntry.cc index db56b64d..f9b889c7 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.cc +++ b/kernel/objects/capability-spinning/objects/CapEntry.cc @@ -128,12 +128,11 @@ namespace mythos { return true; } - optional CapEntry::unlink() + optional CapEntry::unlinkAndUnlockPrev() { MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this)); auto next = Link(_next).withoutFlags(); auto prev = Link(_prev).withoutFlags(); - MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this)); next->_prev.store(prev.value()); prev->_next.store(next.value()); _prev.store(Link().value()); diff --git a/kernel/objects/capability-spinning/objects/CapEntry.hh b/kernel/objects/capability-spinning/objects/CapEntry.hh index c620a2b4..3229d7bd 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.hh +++ b/kernel/objects/capability-spinning/objects/CapEntry.hh @@ -83,7 +83,7 @@ namespace mythos { * allocated. Returns true if zombified. */ bool kill(); - optional unlink(); + optional unlinkAndUnlockPrev(); bool try_lock() { bool ret = !(_next.fetch_or(LOCKED_FLAG) & LOCKED_FLAG); MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this), ret? " locked" : "locking failed!"); diff --git a/kernel/objects/capability-spinning/objects/RevokeOperation.cc b/kernel/objects/capability-spinning/objects/RevokeOperation.cc index 3bad991e..25199d01 100644 --- a/kernel/objects/capability-spinning/objects/RevokeOperation.cc +++ b/kernel/objects/capability-spinning/objects/RevokeOperation.cc @@ -129,7 +129,7 @@ namespace mythos { } auto delRes = leafCap.getPtr()->deleteCap(*leaf, leafCap, *this); if (delRes) { - leaf->unlink(); + leaf->unlinkAndUnlockPrev(); leaf->reset(); } else { // Either tried to delete a portal that is currently deleting diff --git a/kernel/objects/capability-utils/objects/ops.hh b/kernel/objects/capability-utils/objects/ops.hh index a0cc8a9f..11007e92 100644 --- a/kernel/objects/capability-utils/objects/ops.hh +++ b/kernel/objects/capability-utils/objects/ops.hh @@ -75,7 +75,7 @@ namespace mythos { if (!dst.lock_prev()) return true; // was already unlinked, should be empty eventually dst.lock(); dst.kill(); // kill again because someone might have inserted something usable meanwhile - dst.unlink(); + dst.unlinkAndUnlockPrev(); fun(); // perform some caller-defined action while still in an exclusive state dst.reset(); // this markes the entry as writeable again, leaves exclusive state return true; From 9be691677164c4f6af9bd6926f4fd7561bc6f696 Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Fri, 26 Feb 2021 11:59:43 +0100 Subject: [PATCH 17/42] capentry unlock debug output --- kernel/objects/capability-spinning/objects/CapEntry.cc | 8 ++++++++ kernel/objects/capability-spinning/objects/CapEntry.hh | 7 ++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/kernel/objects/capability-spinning/objects/CapEntry.cc b/kernel/objects/capability-spinning/objects/CapEntry.cc index f9b889c7..d902af8a 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.cc +++ b/kernel/objects/capability-spinning/objects/CapEntry.cc @@ -37,7 +37,9 @@ namespace mythos { ASSERT(c.isUsable()); ASSERT(cap().isEmpty()); Link loopLink(this); + MLOG_ERROR(mlog::cap, "this unlocks _next"); _next.store(loopLink.value()); + MLOG_ERROR(mlog::cap, "this unlocks _prev"); _prev.store(loopLink.value()); _cap.store(c.value()); } @@ -65,6 +67,7 @@ namespace mythos { { MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this)); ASSERT(isUnlinked() || cap().isAllocated()); + MLOG_ERROR(mlog::cap, "this unlocks _prev"); _prev.store(Link().value()); _next.store(Link().value()); // mark as empty @@ -108,7 +111,9 @@ namespace mythos { other._prev.store(prev.value()); prev->_next.store(Link(&other).value()); other.commit(thisCap); + MLOG_ERROR(mlog::cap, "this unlocks _prev"); _prev.store(Link().value()); + MLOG_ERROR(mlog::cap, "this unlocks _next"); _next.store(Link().value()); _cap.store(Cap().value()); RETURN(Error::SUCCESS); @@ -135,7 +140,9 @@ namespace mythos { auto prev = Link(_prev).withoutFlags(); next->_prev.store(prev.value()); prev->_next.store(next.value()); + MLOG_ERROR(mlog::cap, "this unlocks _prev"); _prev.store(Link().value()); + MLOG_ERROR(mlog::cap, "this unlocks _next"); _next.store(Link().value()); RETURN(Error::SUCCESS); } @@ -151,6 +158,7 @@ namespace mythos { if (Link(_prev.load()).ptr() == prev) { return Error::SUCCESS; } else { // my _prev has changed in the mean time + MLOG_ERROR(mlog::cap, "this unlocks prev"); prev->unlock(); return Error::RETRY; } diff --git a/kernel/objects/capability-spinning/objects/CapEntry.hh b/kernel/objects/capability-spinning/objects/CapEntry.hh index 3229d7bd..c69b36d3 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.hh +++ b/kernel/objects/capability-spinning/objects/CapEntry.hh @@ -108,7 +108,9 @@ namespace mythos { Error try_lock_prev(); bool lock_prev(); - void unlock_prev() { Link(_prev)->unlock(); } + void unlock_prev() { + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this)); + Link(_prev)->unlock(); } CapEntry* next() { @@ -216,10 +218,13 @@ namespace mythos { auto next = Link(_next.load()).withoutFlags(); next->setPrevPreserveFlags(&targetEntry); + MLOG_ERROR(mlog::cap, "this unlocks _next remotely ", DVAR(targetEntry)); targetEntry._next.store(next.value()); // deleted or revoking can not be set in target._prev // as we allocated target for being inserted + MLOG_ERROR(mlog::cap, "this unlocks _prev remotely ", DVAR(targetEntry)); targetEntry._prev.store(Link(this).value()); + MLOG_ERROR(mlog::cap, "this unlocks _next "); this->_next.store(Link(&targetEntry).value()); // unlocks the parent entry targetEntry.commit(targetCap); // release the target entry as usable RETURN(Error::SUCCESS); From 7da68f2e10e58335bb3b2308ac2a3cc821cde7f0 Mon Sep 17 00:00:00 2001 From: Robert Kuban Date: Fri, 26 Feb 2021 16:19:45 +0100 Subject: [PATCH 18/42] renames lock to lock_next. --- .../capability-spinning/objects/CapEntry.cc | 8 +-- .../capability-spinning/objects/CapEntry.hh | 51 ++++++++++++------- .../objects/RevokeOperation.cc | 18 +++---- .../objects/capability-utils/objects/ops.hh | 2 +- .../memory-amd64/objects/PageMapAmd64.cc | 2 +- 5 files changed, 47 insertions(+), 34 deletions(-) diff --git a/kernel/objects/capability-spinning/objects/CapEntry.cc b/kernel/objects/capability-spinning/objects/CapEntry.cc index d902af8a..eeb9d5b6 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.cc +++ b/kernel/objects/capability-spinning/objects/CapEntry.cc @@ -92,11 +92,11 @@ namespace mythos { other.reset(); THROW(Error::GENERIC_ERROR); } - lock(); + lock_next(); auto thisCap = cap(); if (isRevoking() || !thisCap.isUsable()) { other.reset(); - unlock(); + unlock_next(); unlock_prev(); THROW(Error::INVALID_CAPABILITY); } @@ -154,12 +154,12 @@ namespace mythos { if (!prev) { return Error::GENERIC_ERROR; } - if (prev->try_lock()) { + if (prev->try_lock_next()) { if (Link(_prev.load()).ptr() == prev) { return Error::SUCCESS; } else { // my _prev has changed in the mean time MLOG_ERROR(mlog::cap, "this unlocks prev"); - prev->unlock(); + prev->unlock_next(); return Error::RETRY; } } else return Error::RETRY; diff --git a/kernel/objects/capability-spinning/objects/CapEntry.hh b/kernel/objects/capability-spinning/objects/CapEntry.hh index c69b36d3..b4528eab 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.hh +++ b/kernel/objects/capability-spinning/objects/CapEntry.hh @@ -84,37 +84,50 @@ namespace mythos { bool kill(); optional unlinkAndUnlockPrev(); - bool try_lock() { + + /* lock next functions protect the link to the next CapEntry */ + + bool try_lock_next() + { bool ret = !(_next.fetch_or(LOCKED_FLAG) & LOCKED_FLAG); MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this), ret? " locked" : "locking failed!"); - return ret; } - void lock() { + return ret; + } + + void lock_next() + { int loop = 0; - while (!try_lock()) { - hwthread_pause(); - loop++; - if(loop > 2){ - MLOG_ERROR(mlog::cap, " lockeing failed too many times -> fail"); - while(1); + while (!try_lock_next()) { + hwthread_pause(); +#warning remove counting for production + loop++; + PANIC_MSG(loop < 2," locking failed too many times"); } - } } - void unlock() { + } + void unlock_next() + { MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this)); - auto res = _next.fetch_and(~LOCKED_FLAG); ASSERT(res & LOCKED_FLAG); } + auto res = _next.fetch_and(~LOCKED_FLAG); + ASSERT(res & LOCKED_FLAG); + } /// only for assertions and debugging /// only trust the result if it is false and it should be true - bool is_locked() const { return _next.load() & CapEntry::LOCKED_FLAG; } + bool next_is_locked() const { return _next.load() & CapEntry::LOCKED_FLAG; } + + /* lock prev functions protect the link to the next CapEntry */ Error try_lock_prev(); bool lock_prev(); - void unlock_prev() { + void unlock_prev() + { MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this)); - Link(_prev)->unlock(); } + Link(_prev)->unlock_next(); + } CapEntry* next() { - ASSERT(is_locked()); + ASSERT(next_is_locked()); return Link(_next).ptr(); } @@ -204,11 +217,11 @@ namespace mythos { MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this), DVAR(parentCap), DVAR(targetEntry), DVAR(targetCap)); ASSERT(isKernelAddress(this)); ASSERT(targetEntry.cap().isAllocated()); - lock(); // lock the parent entry, the child is already acquired + lock_next(); // lock the parent entry, the child is already acquired auto curCap = cap(); // lazy-locking: check that we still operate on the same parent capability if (!curCap.isUsable() || curCap != parentCap) { - unlock(); // unlock the parent entry + unlock_next(); // unlock the parent entry targetEntry.reset(); // release exclusive usage and revert to an empty entry THROW(Error::LOST_RACE); } @@ -239,7 +252,7 @@ namespace mythos { if (entry.isLinked()) out << ":linked"; if (entry.isDeleted()) out << ":deleted"; if (entry.isUnlinked()) out << ":unlinked"; - if (entry.is_locked()) out << ":locked"; + if (entry.next_is_locked()) out << ":next_locked"; if (entry.isRevoking()) out << ":revoking"; return out; } diff --git a/kernel/objects/capability-spinning/objects/RevokeOperation.cc b/kernel/objects/capability-spinning/objects/RevokeOperation.cc index 25199d01..8327725e 100644 --- a/kernel/objects/capability-spinning/objects/RevokeOperation.cc +++ b/kernel/objects/capability-spinning/objects/RevokeOperation.cc @@ -85,11 +85,11 @@ namespace mythos { monitor.requestDone(); return; } - entry.lock(); + entry.lock_next(); auto rootCap = entry.cap(); if (!rootCap.isUsable()) { // this is not the cap you are locking for ... - entry.unlock(); + entry.unlock_next(); res->response(t, Error::LOST_RACE); release(); monitor.requestDone(); @@ -99,7 +99,7 @@ namespace mythos { // if some other revoke or delete clears the flag or changes the cap values // all children have been deleted in the mean time and we are done entry.setRevoking(); - entry.unlock(); + entry.unlock_next(); _result = _delete(&entry, rootCap).state(); _startAsyncDelete(t); } @@ -115,14 +115,14 @@ namespace mythos { if (leaf == root && !rootCap.isZombie()) { // this is a revoke, do not delete the root. no more children -> we are done root->finishRevoke(); - root->unlock(); + root->unlock_next(); root->unlock_prev(); RETURN(Error::SUCCESS); } auto leafCap = leaf->cap(); ASSERT(leafCap.isZombie()); if (leafCap.getPtr() == _guarded) { - leaf->unlock(); + leaf->unlock_next(); leaf->unlock_prev(); // attempted to delete guarded object THROW(Error::CYCLIC_DEPENDENCY); @@ -134,7 +134,7 @@ namespace mythos { } else { // Either tried to delete a portal that is currently deleting // or tried to to delete _guarded via a recursive call. - leaf->unlock(); + leaf->unlock_next(); leaf->unlock_prev(); RETHROW(delRes); } @@ -159,12 +159,12 @@ namespace mythos { root->unlock_prev(); return false; } - root->lock(); + root->lock_next(); // compare only value, not the zombie state if (root->cap().asZombie() != rootCap.asZombie()) { // start has a new value // must be the work of another deleter ... success! - root->unlock(); + root->unlock_next(); root->unlock_prev(); return false; } @@ -190,7 +190,7 @@ namespace mythos { // go to next child curEntry->unlock_prev(); nextEntry->kill(); - nextEntry->lock(); + nextEntry->lock_next(); curEntry = nextEntry; continue; } else return curEntry; diff --git a/kernel/objects/capability-utils/objects/ops.hh b/kernel/objects/capability-utils/objects/ops.hh index 11007e92..1f846a7c 100644 --- a/kernel/objects/capability-utils/objects/ops.hh +++ b/kernel/objects/capability-utils/objects/ops.hh @@ -73,7 +73,7 @@ namespace mythos { { if (!dst.kill()) return false; // not killable (allocated but not usable) if (!dst.lock_prev()) return true; // was already unlinked, should be empty eventually - dst.lock(); + dst.lock_next(); dst.kill(); // kill again because someone might have inserted something usable meanwhile dst.unlinkAndUnlockPrev(); fun(); // perform some caller-defined action while still in an exclusive state diff --git a/kernel/objects/memory-amd64/objects/PageMapAmd64.cc b/kernel/objects/memory-amd64/objects/PageMapAmd64.cc index 3f54a4a5..2d14cb11 100644 --- a/kernel/objects/memory-amd64/objects/PageMapAmd64.cc +++ b/kernel/objects/memory-amd64/objects/PageMapAmd64.cc @@ -114,7 +114,7 @@ namespace mythos { if (self.isOriginal()) { MLOG_ERROR(mlog::cap, "delete PageMap", self); for (size_t i = 0; i < num_caps(); ++i) { - if(_cap_table(i).is_locked()) MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, "table is locked and cannot be deleted! -> deadlock detected!"); + if(_cap_table(i).next_is_locked()) MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, "table is locked and cannot be deleted! -> deadlock detected!"); auto res = del.deleteEntry(_cap_table(i)); ASSERT_MSG(res, "Mapped entries must be deletable."); if (!res) RETHROW(res); From 74f3bcc59f76c5ae4102e406f7e75586aed45df0 Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Sat, 27 Feb 2021 07:33:13 +0100 Subject: [PATCH 19/42] PML4 broadcast page fault test --- kernel/app/init-example/app/init.cc | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/kernel/app/init-example/app/init.cc b/kernel/app/init-example/app/init.cc index 1bb8259a..fa5ad6f2 100644 --- a/kernel/app/init-example/app/init.cc +++ b/kernel/app/init-example/app/init.cc @@ -517,7 +517,24 @@ void test_process(){ MLOG_INFO(mlog::app, "Test process finished"); } -void pageMapBug(){ +void pageMapPageFault(){ + MLOG_INFO(mlog::app, "Trigger PageMap page fault"); + + mythos::PortalLock pl(portal); + + mythos::PageMap pm4(capAlloc()); + + auto res = pm4.create(pl, kmem, 4).wait(); + ASSERT(res); + + MLOG_INFO(mlog::app, "Try to delete pm4 -> page fault"); + + capAlloc.free(pm4.cap(), pl); + + MLOG_INFO(mlog::app, "If you can read this, you might have fixed the page fault?!"); +} + +void pageMapDeadlock(){ MLOG_INFO(mlog::app, "Trigger PageMap deadlock"); mythos::PortalLock pl(portal); @@ -567,7 +584,8 @@ int main() //test_processor_allocator(); //test_process(); //test_CgaScreen(); - pageMapBug(); + pageMapPageFault(); + pageMapDeadlock(); char const end[] = "bye, cruel world!"; mythos::syscall_debug(end, sizeof(end)-1); From 7e8d78a707e52b273559445b8b6983c74f86293c Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Sat, 27 Feb 2021 07:33:39 +0100 Subject: [PATCH 20/42] fixed PML4 broadcast page fault --- kernel/boot/apboot-common/boot/DeployHWThread.hh | 2 ++ .../memory-amd64/objects/PML4InvalidationBroadcastAmd64.cc | 1 + 2 files changed, 3 insertions(+) diff --git a/kernel/boot/apboot-common/boot/DeployHWThread.hh b/kernel/boot/apboot-common/boot/DeployHWThread.hh index 946fc25c..e5be3b3f 100644 --- a/kernel/boot/apboot-common/boot/DeployHWThread.hh +++ b/kernel/boot/apboot-common/boot/DeployHWThread.hh @@ -38,6 +38,7 @@ #include "cpu/idle.hh" #include "async/Place.hh" #include "objects/DeleteBroadcast.hh" +#include "objects/PML4InvalidationBroadcastAmd64.hh" #include "objects/SchedulingContext.hh" #include "objects/InterruptControl.hh" #include "boot/memory-layout.h" @@ -78,6 +79,7 @@ struct DeployHWThread { idt.init(); DeleteBroadcast::init(); // depends on hwthread enumeration + PML4InvalidationBroadcast::init(); // depends on hwthread enumeration } void prepare(cpu::ThreadID threadID, cpu::ApicID apicID) diff --git a/kernel/objects/memory-amd64/objects/PML4InvalidationBroadcastAmd64.cc b/kernel/objects/memory-amd64/objects/PML4InvalidationBroadcastAmd64.cc index 9129a0b6..1a0cfcac 100644 --- a/kernel/objects/memory-amd64/objects/PML4InvalidationBroadcastAmd64.cc +++ b/kernel/objects/memory-amd64/objects/PML4InvalidationBroadcastAmd64.cc @@ -58,6 +58,7 @@ namespace mythos { } // propagate PML4InvalidationBroadcast* pnext = this->next; + ASSERT(pnext); while (pnext != start && pnext->home->getCR3() != pml4) pnext = pnext->next; if (pnext != start) { MLOG_DETAIL(mlog::cap, "relay pml4 invalidation"); From efc4adea174f1b40c0bae94fc9f3c4bac129d205 Mon Sep 17 00:00:00 2001 From: Robert Kuban Date: Mon, 1 Mar 2021 11:09:46 +0100 Subject: [PATCH 21/42] adds lock_cap. --- .../capability-spinning/objects/CapEntry.cc | 4 +- .../capability-spinning/objects/CapEntry.hh | 38 ++++++++++++++++++- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/kernel/objects/capability-spinning/objects/CapEntry.cc b/kernel/objects/capability-spinning/objects/CapEntry.cc index eeb9d5b6..70be5751 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.cc +++ b/kernel/objects/capability-spinning/objects/CapEntry.cc @@ -67,7 +67,6 @@ namespace mythos { { MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this)); ASSERT(isUnlinked() || cap().isAllocated()); - MLOG_ERROR(mlog::cap, "this unlocks _prev"); _prev.store(Link().value()); _next.store(Link().value()); // mark as empty @@ -106,12 +105,11 @@ namespace mythos { next->setPrevPreserveFlags(&other); other._next.store(next.value()); - // deleted or revoking can not be set in other._prev + // deletion, deleted or revoking can not be set in other._prev // as we allocated other for moving other._prev.store(prev.value()); prev->_next.store(Link(&other).value()); other.commit(thisCap); - MLOG_ERROR(mlog::cap, "this unlocks _prev"); _prev.store(Link().value()); MLOG_ERROR(mlog::cap, "this unlocks _next"); _next.store(Link().value()); diff --git a/kernel/objects/capability-spinning/objects/CapEntry.hh b/kernel/objects/capability-spinning/objects/CapEntry.hh index b4528eab..85e5b384 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.hh +++ b/kernel/objects/capability-spinning/objects/CapEntry.hh @@ -104,6 +104,7 @@ namespace mythos { PANIC_MSG(loop < 2," locking failed too many times"); } } + void unlock_next() { MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this)); @@ -111,6 +112,33 @@ namespace mythos { ASSERT(res & LOCKED_FLAG); } + /* deletion lock functions protect the deletion of a object */ + + bool try_lock_cap() + { + bool ret = !(_prev.fetch_or(LOCKED_FLAG) & LOCKED_FLAG); + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this), ret? " locked" : "locking failed!"); + return ret; + } + + void lock_cap() + { + int loop = 0; + while (!try_lock_cap()) { + hwthread_pause(); +#warning remove counting for production + loop++; + PANIC_MSG(loop < 2," locking failed too many times"); + } + } + + void unlock_cap() + { + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this)); + auto res = _prev.fetch_and(~LOCKED_FLAG); + ASSERT(res & LOCKED_FLAG); + } + /// only for assertions and debugging /// only trust the result if it is false and it should be true bool next_is_locked() const { return _next.load() & CapEntry::LOCKED_FLAG; } @@ -144,9 +172,15 @@ namespace mythos { // called by move and insertAfter void setPrevPreserveFlags(CapEntry* ptr); + // lock flag in _next and _prev + // _next protects the link to the next entry (lock_next) + // _prev protects the capability in the entry from being changed (lock_cap) static constexpr uintlink_t LOCKED_FLAG = 1; - static constexpr uintlink_t REVOKING_FLAG = 1 << 1; - static constexpr uintlink_t DELETED_FLAG = 1 << 2; + + // flags describing the entry in _prev + static constexpr uintlink_t REVOKING_FLAG = 1 << 1; // prevents from moving + static constexpr uintlink_t DELETED_FLAG = 1 << 2; // prevents from inserting in soon-to-be-deleted object + static constexpr uintlink_t FLAG_MASK = 7; static_assert((DELETED_FLAG | REVOKING_FLAG | FLAG_MASK) == FLAG_MASK, "prev flags do not fit"); From 9b24ea6fbcb964d763395c04c6058b5b68887be9 Mon Sep 17 00:00:00 2001 From: Robert Kuban Date: Mon, 1 Mar 2021 18:47:04 +0100 Subject: [PATCH 22/42] searches for leaf locklessy. --- .../capability-spinning/objects/CapEntry.cc | 30 +++- .../capability-spinning/objects/CapEntry.hh | 26 +-- .../objects/RevokeOperation.cc | 149 ++++++++---------- .../objects/RevokeOperation.hh | 3 +- .../objects/capability-utils/objects/ops.hh | 3 +- .../memory-amd64/objects/PageMapAmd64.cc | 2 +- 6 files changed, 113 insertions(+), 100 deletions(-) diff --git a/kernel/objects/capability-spinning/objects/CapEntry.cc b/kernel/objects/capability-spinning/objects/CapEntry.cc index 70be5751..863d9a6a 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.cc +++ b/kernel/objects/capability-spinning/objects/CapEntry.cc @@ -91,15 +91,18 @@ namespace mythos { other.reset(); THROW(Error::GENERIC_ERROR); } + lock_cap(); lock_next(); auto thisCap = cap(); if (isRevoking() || !thisCap.isUsable()) { other.reset(); unlock_next(); + unlock_cap(); unlock_prev(); THROW(Error::INVALID_CAPABILITY); } + // using these values removes lock auto next= Link(_next).withoutFlags(); auto prev= Link(_prev).withoutFlags(); @@ -108,10 +111,12 @@ namespace mythos { // deletion, deleted or revoking can not be set in other._prev // as we allocated other for moving other._prev.store(prev.value()); + MLOG_ERROR(mlog::cap, "this unlocks prev"); prev->_next.store(Link(&other).value()); other.commit(thisCap); + MLOG_ERROR(mlog::cap, "this unlocks cap"); _prev.store(Link().value()); - MLOG_ERROR(mlog::cap, "this unlocks _next"); + MLOG_ERROR(mlog::cap, "this unlocks next"); _next.store(Link().value()); _cap.store(Cap().value()); RETURN(Error::SUCCESS); @@ -131,15 +136,24 @@ namespace mythos { return true; } - optional CapEntry::unlinkAndUnlockPrev() + bool CapEntry::kill(Cap expected) + { + CapValue expectedValue = expected.value(); + MLOG_DETAIL(mlog::cap, this, ".kill", DVAR(expected)); + return _cap.compare_exchange_strong(expectedValue, expected.asZombie().value()); + } + + + optional CapEntry::unlinkAndUnlockLinks() { MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this)); - auto next = Link(_next).withoutFlags(); - auto prev = Link(_prev).withoutFlags(); - next->_prev.store(prev.value()); - prev->_next.store(next.value()); - MLOG_ERROR(mlog::cap, "this unlocks _prev"); - _prev.store(Link().value()); + auto next = Link(_next); + auto prev = Link(_prev); +#warning this does not preserve the flags of next :( + next->_prev.store(prev.withoutFlags().value()); + MLOG_ERROR(mlog::cap, "this unlocks _next of predecessor"); + prev->_next.store(next.withoutFlags().value()); + _prev.store(Link().withoutPtr().value()); MLOG_ERROR(mlog::cap, "this unlocks _next"); _next.store(Link().value()); RETURN(Error::SUCCESS); diff --git a/kernel/objects/capability-spinning/objects/CapEntry.hh b/kernel/objects/capability-spinning/objects/CapEntry.hh index 85e5b384..69bacc23 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.hh +++ b/kernel/objects/capability-spinning/objects/CapEntry.hh @@ -83,7 +83,9 @@ namespace mythos { * allocated. Returns true if zombified. */ bool kill(); - optional unlinkAndUnlockPrev(); + bool kill(Cap expected); + + optional unlinkAndUnlockLinks(); /* lock next functions protect the link to the next CapEntry */ @@ -101,7 +103,7 @@ namespace mythos { hwthread_pause(); #warning remove counting for production loop++; - PANIC_MSG(loop < 2," locking failed too many times"); + PANIC_MSG(loop < 3, "locking next failed too many times"); } } @@ -128,7 +130,7 @@ namespace mythos { hwthread_pause(); #warning remove counting for production loop++; - PANIC_MSG(loop < 2," locking failed too many times"); + PANIC_MSG(loop < 3," locking failed too many times"); } } @@ -147,6 +149,7 @@ namespace mythos { Error try_lock_prev(); bool lock_prev(); + void unlock_prev() { MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this)); @@ -155,7 +158,6 @@ namespace mythos { CapEntry* next() { - ASSERT(next_is_locked()); return Link(_next).ptr(); } @@ -197,9 +199,10 @@ namespace mythos { CapEntry* operator->() { ASSERT(ptr()); return ptr(); } Link withFlags(uintlink_t flags) const { return Link(_offset(), flags); } - Link withoutFlags() const { return Link(_offset(), 0); } + Link withoutFlags() const { return withFlags(0); } Link withPtr(CapEntry* ptr) const { return Link(ptr, flags()); } + Link withoutPtr() const { return withPtr(nullptr); } CapEntry* ptr() const { @@ -251,11 +254,15 @@ namespace mythos { MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this), DVAR(parentCap), DVAR(targetEntry), DVAR(targetCap)); ASSERT(isKernelAddress(this)); ASSERT(targetEntry.cap().isAllocated()); - lock_next(); // lock the parent entry, the child is already acquired + // lock the parent entry, the child is already acquired + lock_cap(); + lock_next(); auto curCap = cap(); // lazy-locking: check that we still operate on the same parent capability if (!curCap.isUsable() || curCap != parentCap) { - unlock_next(); // unlock the parent entry + // unlock the parent entry + unlock_next(); + unlock_cap(); targetEntry.reset(); // release exclusive usage and revert to an empty entry THROW(Error::LOST_RACE); } @@ -265,14 +272,15 @@ namespace mythos { auto next = Link(_next.load()).withoutFlags(); next->setPrevPreserveFlags(&targetEntry); - MLOG_ERROR(mlog::cap, "this unlocks _next remotely ", DVAR(targetEntry)); + // dest was never locked MLOG_ERROR(mlog::cap, "this unlocks next in child", DVAR(targetEntry)); targetEntry._next.store(next.value()); // deleted or revoking can not be set in target._prev // as we allocated target for being inserted - MLOG_ERROR(mlog::cap, "this unlocks _prev remotely ", DVAR(targetEntry)); + // dest was never locked MLOG_ERROR(mlog::cap, "this unlocks cap in child", DVAR(targetEntry)); targetEntry._prev.store(Link(this).value()); MLOG_ERROR(mlog::cap, "this unlocks _next "); this->_next.store(Link(&targetEntry).value()); // unlocks the parent entry + unlock_cap(); targetEntry.commit(targetCap); // release the target entry as usable RETURN(Error::SUCCESS); } diff --git a/kernel/objects/capability-spinning/objects/RevokeOperation.cc b/kernel/objects/capability-spinning/objects/RevokeOperation.cc index 8327725e..a2ec3bfe 100644 --- a/kernel/objects/capability-spinning/objects/RevokeOperation.cc +++ b/kernel/objects/capability-spinning/objects/RevokeOperation.cc @@ -85,11 +85,11 @@ namespace mythos { monitor.requestDone(); return; } - entry.lock_next(); + entry.lock_cap(); auto rootCap = entry.cap(); if (!rootCap.isUsable()) { // this is not the cap you are locking for ... - entry.unlock_next(); + entry.unlock_cap(); res->response(t, Error::LOST_RACE); release(); monitor.requestDone(); @@ -99,7 +99,7 @@ namespace mythos { // if some other revoke or delete clears the flag or changes the cap values // all children have been deleted in the mean time and we are done entry.setRevoking(); - entry.unlock_next(); + entry.unlock_cap(); _result = _delete(&entry, rootCap).state(); _startAsyncDelete(t); } @@ -108,92 +108,83 @@ namespace mythos { { MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(root), DVAR(rootCap)); CapEntry* leaf; + Cap leafCap; do { - if (_startTraversal(root, rootCap)) { - leaf = _findLockedLeaf(root); - MLOG_ERROR(mlog::cap, "_findLockedLeaf returned", DVAR(*leaf), DVAR(rootCap)); - if (leaf == root && !rootCap.isZombie()) { - // this is a revoke, do not delete the root. no more children -> we are done - root->finishRevoke(); - root->unlock_next(); - root->unlock_prev(); - RETURN(Error::SUCCESS); - } - auto leafCap = leaf->cap(); - ASSERT(leafCap.isZombie()); - if (leafCap.getPtr() == _guarded) { - leaf->unlock_next(); - leaf->unlock_prev(); - // attempted to delete guarded object - THROW(Error::CYCLIC_DEPENDENCY); - } - auto delRes = leafCap.getPtr()->deleteCap(*leaf, leafCap, *this); - if (delRes) { - leaf->unlinkAndUnlockPrev(); - leaf->reset(); - } else { - // Either tried to delete a portal that is currently deleting - // or tried to to delete _guarded via a recursive call. - leaf->unlock_next(); - leaf->unlock_prev(); - RETHROW(delRes); - } - } else RETURN(Error::SUCCESS); // could not restart, must be done + // compare only value, not the zombie state + if (root->cap().asZombie() != rootCap.asZombie()) { + // start has a new value + // must be the work of another deleter ... success! + RETURN(Error::SUCCESS); // could not restart, must be done + } + if (!_findLeaf(root, rootCap, leaf, leafCap)) continue; + MLOG_ERROR(mlog::cap, "_findLockedLeaf returned", DVAR(*leaf), DVAR(rootCap)); + if (leaf == root && !rootCap.isZombie()) { + // this is a revoke, do not delete the root. no more children -> we are done + root->finishRevoke(); + RETURN(Error::SUCCESS); + } + ASSERT(leafCap.isZombie()); + if (leafCap.getPtr() == _guarded) { + leaf->unlock_cap(); + // attempted to delete guarded object + THROW(Error::CYCLIC_DEPENDENCY); + } + leaf->lock_cap(); + if (leaf->cap() != leafCap) { + MLOG_DETAIL(mlog::cap, "leaf cap changed concurrently"); + leaf->unlock_cap(); + continue; + } + auto delRes = leafCap.getPtr()->deleteCap(*leaf, leafCap, *this); + auto prevres = leaf->lock_prev(); + ASSERT_MSG(prevres, "somebody unlinked CapEntry currently in unlinking process"); + leaf->lock_next(); + if (delRes) { + leaf->unlinkAndUnlockLinks(); + leaf->reset(); + } else { + // deletion failed + // Either tried to delete a portal that is currently deleting + // or tried to to delete _guarded via a recursive call. + leaf->unlock_cap(); + RETHROW(delRes); + } } while (leaf != root); // deleted root RETURN(Error::SUCCESS); } - bool RevokeOperation::_startTraversal(CapEntry* root, Cap rootCap) - { - MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(root), DVAR(rootCap) ); - if (!root->lock_prev()) { - // start is currently unlinked - // must be the work of another deleter ... success! - return false; - } - if (root->prev() == root) { - // this is the actual root of the tree - // and has no children - // avoid deadlocks and finish the operation - root->unlock_prev(); - return false; - } - root->lock_next(); - // compare only value, not the zombie state - if (root->cap().asZombie() != rootCap.asZombie()) { - // start has a new value - // must be the work of another deleter ... success! - root->unlock_next(); - root->unlock_prev(); - return false; - } - return true; - } - - CapEntry* RevokeOperation::_findLockedLeaf(CapEntry* root) + // not sure if we even need that locking + bool RevokeOperation::_findLeaf(CapEntry* const root, Cap const rootCap, CapEntry*& leafEntry, Cap& leafCap) { MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(root) ); - auto curEntry = root; + leafEntry = root; + leafCap = rootCap; while (true) { - auto curCap = curEntry->cap(); - auto nextEntry = curEntry->next(); - // wait for potencially allocated cap to become usable/zombie - Cap nextCap; - for (nextCap = nextEntry->cap(); - nextCap.isAllocated(); - nextCap = nextEntry->cap()) { - ASSERT(!nextEntry->isDeleted()); - hwthread_pause(); + auto nextEntry = leafEntry->next(); + if (nextEntry) { + Cap nextCap; + // wait for potencially allocated cap to become usable/zombie + for (nextCap = nextEntry->cap(); + nextCap.isAllocated(); + nextCap = nextEntry->cap()) { + ASSERT(!nextEntry->isDeleted()); + hwthread_pause(); + } + if (cap::isParentOf(*leafEntry, leafCap, *nextEntry, nextCap)) { + if (!nextEntry->kill(nextCap)) { + MLOG_DETAIL(mlog::cap, "cap to be killed changed concurrently"); + return false; + } + // go to next child + leafEntry = nextEntry; + leafCap = nextCap.asZombie(); + continue; + } else return true; + } else { + MLOG_DETAIL(mlog::cap, "found dead end scanning for leaf"); + return false; // restart at root } - if (cap::isParentOf(*curEntry, curCap, *nextEntry, nextCap)) { - // go to next child - curEntry->unlock_prev(); - nextEntry->kill(); - nextEntry->lock_next(); - curEntry = nextEntry; - continue; - } else return curEntry; } } diff --git a/kernel/objects/capability-spinning/objects/RevokeOperation.hh b/kernel/objects/capability-spinning/objects/RevokeOperation.hh index 6ad3a33c..593f156c 100644 --- a/kernel/objects/capability-spinning/objects/RevokeOperation.hh +++ b/kernel/objects/capability-spinning/objects/RevokeOperation.hh @@ -107,8 +107,7 @@ private: void _deleteObject(Tasklet* t); optional _delete(CapEntry* root, Cap rootCap); - bool _startTraversal(CapEntry* root, Cap rootCap); - CapEntry* _findLockedLeaf(CapEntry* root); + bool _findLeaf(CapEntry* const root, Cap const rootCap, CapEntry*& leaf, Cap& leafCap); void _startAsyncDelete(Tasklet* t); diff --git a/kernel/objects/capability-utils/objects/ops.hh b/kernel/objects/capability-utils/objects/ops.hh index 1f846a7c..83cf5525 100644 --- a/kernel/objects/capability-utils/objects/ops.hh +++ b/kernel/objects/capability-utils/objects/ops.hh @@ -73,9 +73,10 @@ namespace mythos { { if (!dst.kill()) return false; // not killable (allocated but not usable) if (!dst.lock_prev()) return true; // was already unlinked, should be empty eventually + dst.lock_cap(); dst.lock_next(); dst.kill(); // kill again because someone might have inserted something usable meanwhile - dst.unlinkAndUnlockPrev(); + dst.unlinkAndUnlockLinks(); fun(); // perform some caller-defined action while still in an exclusive state dst.reset(); // this markes the entry as writeable again, leaves exclusive state return true; diff --git a/kernel/objects/memory-amd64/objects/PageMapAmd64.cc b/kernel/objects/memory-amd64/objects/PageMapAmd64.cc index 2d14cb11..ad337076 100644 --- a/kernel/objects/memory-amd64/objects/PageMapAmd64.cc +++ b/kernel/objects/memory-amd64/objects/PageMapAmd64.cc @@ -387,7 +387,7 @@ namespace mythos { auto res = visitTables(&_pm_table(0), level(), op); *failaddr = op.failaddr; *faillevel = op.current_level; - RETHROW(res.state()); + RETURN(res.state()); } Error PageMap::invokeInstallMap(Tasklet*, Cap self, IInvocation* msg) From ae1bfc3160af3381671d73a36fb2ac9a844d8977 Mon Sep 17 00:00:00 2001 From: Robert Kuban Date: Mon, 1 Mar 2021 19:01:16 +0100 Subject: [PATCH 23/42] fixed overwritten flags. --- kernel/objects/capability-spinning/objects/CapEntry.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/objects/capability-spinning/objects/CapEntry.cc b/kernel/objects/capability-spinning/objects/CapEntry.cc index 863d9a6a..93ef532b 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.cc +++ b/kernel/objects/capability-spinning/objects/CapEntry.cc @@ -149,8 +149,7 @@ namespace mythos { MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this)); auto next = Link(_next); auto prev = Link(_prev); -#warning this does not preserve the flags of next :( - next->_prev.store(prev.withoutFlags().value()); + next->setPrevPreserveFlags(prev.ptr()); MLOG_ERROR(mlog::cap, "this unlocks _next of predecessor"); prev->_next.store(next.withoutFlags().value()); _prev.store(Link().withoutPtr().value()); From 9469d8baf56c5fd3dd132cc4546789939c806117 Mon Sep 17 00:00:00 2001 From: Robert Kuban Date: Mon, 1 Mar 2021 19:30:16 +0100 Subject: [PATCH 24/42] fixes lock order. --- kernel/objects/capability-spinning/objects/CapEntry.cc | 5 +++-- kernel/objects/capability-utils/objects/ops.hh | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/kernel/objects/capability-spinning/objects/CapEntry.cc b/kernel/objects/capability-spinning/objects/CapEntry.cc index 93ef532b..363ff9a7 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.cc +++ b/kernel/objects/capability-spinning/objects/CapEntry.cc @@ -87,18 +87,19 @@ namespace mythos { MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this), DVAR(other)); ASSERT(other.cap().isAllocated()); ASSERT(!other.isLinked()); + lock_cap(); if (!lock_prev()) { + unlock_cap(); other.reset(); THROW(Error::GENERIC_ERROR); } - lock_cap(); lock_next(); auto thisCap = cap(); if (isRevoking() || !thisCap.isUsable()) { other.reset(); unlock_next(); - unlock_cap(); unlock_prev(); + unlock_cap(); THROW(Error::INVALID_CAPABILITY); } diff --git a/kernel/objects/capability-utils/objects/ops.hh b/kernel/objects/capability-utils/objects/ops.hh index 83cf5525..068c3074 100644 --- a/kernel/objects/capability-utils/objects/ops.hh +++ b/kernel/objects/capability-utils/objects/ops.hh @@ -72,8 +72,11 @@ namespace mythos { bool resetReference(CapEntry& dst, const COMMITFUN& fun) { if (!dst.kill()) return false; // not killable (allocated but not usable) - if (!dst.lock_prev()) return true; // was already unlinked, should be empty eventually dst.lock_cap(); + if (!dst.lock_prev()) { + dst.unlock_cap(); + return true; // was already unlinked, should be empty eventually + } dst.lock_next(); dst.kill(); // kill again because someone might have inserted something usable meanwhile dst.unlinkAndUnlockLinks(); From 0cb2143fdd6429eb1afe573bebee6182411186fb Mon Sep 17 00:00:00 2001 From: Robert Kuban Date: Mon, 1 Mar 2021 19:54:15 +0100 Subject: [PATCH 25/42] adds a bit more documentation. --- .../capability-spinning/objects/CapEntry.hh | 10 +++++++- .../objects/RevokeOperation.hh | 23 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/kernel/objects/capability-spinning/objects/CapEntry.hh b/kernel/objects/capability-spinning/objects/CapEntry.hh index 69bacc23..c0eba6b6 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.hh +++ b/kernel/objects/capability-spinning/objects/CapEntry.hh @@ -44,7 +44,15 @@ namespace mythos { * thus prev and next of root are locked independently * * operations that write to the capability - * or flags (zombie) must lock both next and prev + * or call deleteCap on an obejct must lock_cap + * + * lock order: lock_cap, lock_prev, lock_next + * + * acquired status means someone exclusively acquired an unlinked CapEntry + * therefore no races with others trying to insert it. + * + * acquired status must be only hold shortly + * */ class CapEntry { diff --git a/kernel/objects/capability-spinning/objects/RevokeOperation.hh b/kernel/objects/capability-spinning/objects/RevokeOperation.hh index 593f156c..0ec3c42b 100644 --- a/kernel/objects/capability-spinning/objects/RevokeOperation.hh +++ b/kernel/objects/capability-spinning/objects/RevokeOperation.hh @@ -39,6 +39,29 @@ namespace mythos { +/** + * The revoke operation consists of 2 phases seperated + * by an invalidation broadcast. + * + * 1. synchronous phase removes entries from the capability tree + * 2. delete broadcast ensures there are no more references in stack + * 3. asynchronous phase interacts with a KM to recycle objects + * + * 1. synchronous phase + * + * - Traverses the tree starting from an node (root of that subtree). + * - this traverses the list without locking + * - It finds a leaf, killing all the capabilities inbetween. + * - the leaf is deleted by killing deleteCap of the object (protected by lock_cap). + * if that succeedes, the CapEntry MUST be removed from the tree, as we can't do that twice + * and can't hold lock_cap forever. + * - If there are problems because of concurrent access, the operation + * restarts at the root of the subtree. + * - If we can't fix problems synchronously, we switch to asynch. phase + * without finishing, reporting "Error::RETRY" to the user. + * - a guarded object is the object containing the RevokeOperation, it can't be deleted + * + */ class RevokeOperation : public IResult , protected IDeleter From fb20cf931b26164ebaf4b07a2d364d00bca101aa Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Tue, 2 Mar 2021 10:52:41 +0100 Subject: [PATCH 26/42] provide original capmap capability to user --- kernel/objects/capmap/objects/CapMap.cc | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/kernel/objects/capmap/objects/CapMap.cc b/kernel/objects/capmap/objects/CapMap.cc index 3615bd21..723175a4 100644 --- a/kernel/objects/capmap/objects/CapMap.cc +++ b/kernel/objects/capmap/objects/CapMap.cc @@ -66,15 +66,15 @@ namespace mythos { CapMapFactory::factory(CapEntry* dstEntry, CapEntry* memEntry, Cap memCap, IAllocator* mem, CapPtrDepth indexbits, CapPtrDepth guardbits, CapPtr guard) { - auto obj = initial(memEntry, memCap, mem, indexbits, guardbits, guard); - if (!obj) RETHROW(obj); - auto& root = obj->getRoot(); - auto cap = root.cap(); - // Just a reference is stored in the target capability entry. - // The CapMap contains its original capability internally - // in order to resolve cyclic dependencies during deletion. - auto res = cap::inherit(root, cap, *dstEntry, cap.asReference()); - if (!res) RETHROW(res); // the object was deleted concurrently + auto ptr = mem->alloc(CapMap::size(indexbits), 64); + if (!ptr) RETHROW(ptr); + auto obj = new(*ptr) CapMap(mem, indexbits, guardbits, guard); + auto cap = Cap(obj).withData(CapMapData().writable(true)); + auto res = cap::inherit(*memEntry, memCap, *dstEntry, cap); + if (!res) { + mem->free(*ptr, CapMap::size(indexbits)); + RETHROW(res); + } return obj; } @@ -86,7 +86,9 @@ namespace mythos { optional CapMap::deleteCap(CapEntry&, Cap self, IDeleter& del) { + MLOG_INFO(mlog::cap, "CapMap::deleteCap"); if (self.isOriginal()) { + MLOG_DETAIL(mlog::cap, "delete original"); // delete all entries, leaves them in a locked state (allocated) // in order to prevent concurrent insertion of new caps. for (size_t i=0; i Date: Tue, 2 Mar 2021 11:01:55 +0100 Subject: [PATCH 27/42] removed move operation of capmap to avaoid cyclic dependencies (process lib needs to be reworked) --- kernel/app/init-example/app/init.cc | 16 ++- .../invocation/mythos/protocol/CapMap.hh | 12 -- kernel/objects/capmap/objects/CapMap.cc | 17 +-- kernel/objects/capmap/objects/CapMap.hh | 1 - kernel/runtime/kobject/runtime/CapMap.hh | 5 - kernel/runtime/process/runtime/process.hh | 103 +++++++++--------- 6 files changed, 68 insertions(+), 86 deletions(-) diff --git a/kernel/app/init-example/app/init.cc b/kernel/app/init-example/app/init.cc index e27c8497..4b81f6fc 100644 --- a/kernel/app/init-example/app/init.cc +++ b/kernel/app/init-example/app/init.cc @@ -517,6 +517,19 @@ void test_process(){ MLOG_INFO(mlog::app, "Test process finished"); } +void testCapMapDeletion(){ + MLOG_INFO(mlog::app, "Test CapMap deletion"); + + mythos::PortalLock pl(portal); + mythos::CapMap cs(capAlloc()); + + auto res = cs.create(pl, kmem, CapPtrDepth(12), CapPtrDepth(20), CapPtr(0)).wait(); + ASSERT(res); + + capAlloc.free(cs.cap(), pl); + MLOG_INFO(mlog::app, "Test CapMap deletion finished"); +} + int main() { char const str[] = "Hello world!"; @@ -535,8 +548,9 @@ int main() test_pthreads(); test_Rapl(); test_processor_allocator(); - test_process(); + //test_process(); //test_CgaScreen(); + testCapMapDeletion(); char const end[] = "bye, cruel world!"; mythos::syscall_debug(end, sizeof(end)-1); diff --git a/kernel/mythos/invocation/mythos/protocol/CapMap.hh b/kernel/mythos/invocation/mythos/protocol/CapMap.hh index c3fb1689..cb9867d7 100644 --- a/kernel/mythos/invocation/mythos/protocol/CapMap.hh +++ b/kernel/mythos/invocation/mythos/protocol/CapMap.hh @@ -37,7 +37,6 @@ namespace mythos { enum Methods : uint8_t { DERIVE, REFERENCE, - MOVE, DELETE, REVOKE }; @@ -90,16 +89,6 @@ namespace mythos { CapRequest request; }; - struct Move : public BinaryOp { - constexpr static uint16_t label = (proto<<8) + MOVE; - - Move(CapPtr src, uint8_t srcDepth, - CapPtr dstCS, CapPtr dst, uint8_t dstDepth) - : BinaryOp(label, getLength(this), src, srcDepth, dstCS, dst, dstDepth) - {} - - }; - struct Delete : public InvocationBase { constexpr static uint16_t label = (proto<<8) + DELETE; @@ -142,7 +131,6 @@ namespace mythos { switch(Methods(m)) { case REFERENCE: return obj->invokeReference(args...); case DERIVE: return obj->invokeDerive(args...); - case MOVE: return obj->invokeMove(args...); case DELETE: return obj->invokeDelete(args...); case REVOKE: return obj->invokeRevoke(args...); default: return Error::NOT_IMPLEMENTED; diff --git a/kernel/objects/capmap/objects/CapMap.cc b/kernel/objects/capmap/objects/CapMap.cc index 723175a4..1b926f01 100644 --- a/kernel/objects/capmap/objects/CapMap.cc +++ b/kernel/objects/capmap/objects/CapMap.cc @@ -124,7 +124,7 @@ namespace mythos { void CapMap::invoke(Tasklet* t, Cap self, IInvocation* msg) { - /// @todo Monitor might not be neccessary for derive, reference, move + /// @todo Monitor might not be neccessary for derive, reference monitor.request(t, [=](Tasklet* t){ Error err = Error::NOT_IMPLEMENTED; switch (msg->getProtocol()) { @@ -188,21 +188,6 @@ namespace mythos { return cap::reference(*srcRef->entry, *dstRef->entry, srcRef->entry->cap(), data.request).state(); } - Error CapMap::invokeMove(Tasklet*, Cap cap, IInvocation* msg) - { - auto data = msg->getMessage()->read(); - // retrieve dst cap entry - auto dstRef = lookupDst(cap, msg, data); - if (!dstRef) return dstRef.state(); - // retrieve source cap entry - auto srcRef = this->lookup(cap, data.srcPtr(), data.srcDepth, true); - if (!srcRef) return srcRef.state(); - // move - auto res = dstRef->entry->acquire(); - if (!res) { return res.state(); } - return srcRef->entry->moveTo(*dstRef->entry).state(); - } - Error CapMap::invokeDelete(Tasklet*, Cap cap, IInvocation* msg) { auto data = msg->getMessage()->read(); diff --git a/kernel/objects/capmap/objects/CapMap.hh b/kernel/objects/capmap/objects/CapMap.hh index 51b7a967..6bc3c757 100644 --- a/kernel/objects/capmap/objects/CapMap.hh +++ b/kernel/objects/capmap/objects/CapMap.hh @@ -75,7 +75,6 @@ public: // IKernelObject interface Error invokeReference(Tasklet*, Cap, IInvocation*); Error invokeDerive(Tasklet*, Cap, IInvocation*); - Error invokeMove(Tasklet*, Cap, IInvocation*); Error invokeDelete(Tasklet*, Cap, IInvocation*); Error invokeRevoke(Tasklet*, Cap, IInvocation*); Error getDebugInfo(Cap, IInvocation*); diff --git a/kernel/runtime/kobject/runtime/CapMap.hh b/kernel/runtime/kobject/runtime/CapMap.hh index 945e9edf..f93970c1 100644 --- a/kernel/runtime/kobject/runtime/CapMap.hh +++ b/kernel/runtime/kobject/runtime/CapMap.hh @@ -57,11 +57,6 @@ namespace mythos { return pr.invoke(_cap, src, srcDepth, dstCs, dst, dstDepth, req); } - PortalFuture move(PortalLock pr, CapPtr src, CapPtrDepth srcDepth, - CapPtr dstCs, CapPtr dst, CapPtrDepth dstDepth) { - return pr.invoke(_cap, src, srcDepth, dstCs, dst, dstDepth); - } - PortalFuture deleteCap(PortalLock pr, CapPtr src, CapPtrDepth srcDepth) { return pr.invoke(_cap, src, srcDepth); } diff --git a/kernel/runtime/process/runtime/process.hh b/kernel/runtime/process/runtime/process.hh index 77c9cd7d..76df41bf 100644 --- a/kernel/runtime/process/runtime/process.hh +++ b/kernel/runtime/process/runtime/process.hh @@ -128,10 +128,10 @@ class Process{ res = myAS.removeMap(pl, tmp_vaddr, 3).wait(); TEST(res); - MLOG_DETAIL(mlog::app, " move frame"); - res = myCS.move(pl, f.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(f.cap()); + //MLOG_DETAIL(mlog::app, " move frame"); + //res = myCS.move(pl, f.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); + //TEST(res); + //capAlloc.freeEmpty(f.cap()); MLOG_DETAIL(mlog::app, " delete tables"); capAlloc.free(pm3, pl); @@ -142,7 +142,8 @@ class Process{ optional createProcess(PortalLock& pl){ MLOG_INFO(mlog::app, __func__); - + MLOG_ERROR(mlog::app, "process needs to be reworked!"); + return 0; /* create CapMap */ MLOG_DETAIL(mlog::app, "create CapMap ..."); auto res = cs.create(pl, kmem, CapPtrDepth(12), CapPtrDepth(20), CapPtr(0)).wait(); @@ -302,9 +303,9 @@ class Process{ .suspended(true) .invokeVia(pl).wait(); TEST(res); - MLOG_DETAIL(mlog::app, "move SC"); - res = myCS.move(pl, sc->cap, max_cap_depth, cs.cap(), sc->cap, max_cap_depth).wait(); - TEST(res); + //MLOG_DETAIL(mlog::app, "move SC"); + //res = myCS.move(pl, sc->cap, max_cap_depth, cs.cap(), sc->cap, max_cap_depth).wait(); + //TEST(res); /* create portal */ MLOG_DETAIL(mlog::app, "create Portal ..."); @@ -318,66 +319,66 @@ class Process{ TEST(res); MLOG_DETAIL(mlog::app, " move Portal"); - res = myCS.move(pl, port.cap(), max_cap_depth, cs.cap(), init::PORTAL, max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(port.cap()); + //res = myCS.move(pl, port.cap(), max_cap_depth, cs.cap(), init::PORTAL, max_cap_depth).wait(); + //TEST(res); + //capAlloc.freeEmpty(port.cap()); - MLOG_DETAIL(mlog::app, " move info frame"); - res = myCS.move(pl, infoFrame.cap(), max_cap_depth, cs.cap(), init::INFO_FRAME, max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(infoFrame.cap()); + //MLOG_DETAIL(mlog::app, " move info frame"); + //res = myCS.move(pl, infoFrame.cap(), max_cap_depth, cs.cap(), init::INFO_FRAME, max_cap_depth).wait(); + //TEST(res); + //capAlloc.freeEmpty(infoFrame.cap()); /* move tables */ MLOG_DETAIL(mlog::app, "move tables ..."); - res = myCS.move(pl, pm3.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm3.cap()); + //res = myCS.move(pl, pm3.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); + //TEST(res); + //capAlloc.freeEmpty(pm3.cap()); - res = myCS.move(pl, pm2.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm2.cap()); + //res = myCS.move(pl, pm2.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); + //TEST(res); + //capAlloc.freeEmpty(pm2.cap()); - res = myCS.move(pl, pm10.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm10.cap()); + //res = myCS.move(pl, pm10.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); + //TEST(res); + //capAlloc.freeEmpty(pm10.cap()); - res = myCS.move(pl, pm11.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm11.cap()); + //res = myCS.move(pl, pm11.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); + //TEST(res); + //capAlloc.freeEmpty(pm11.cap()); - res = myCS.move(pl, pm12.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm12.cap()); + //res = myCS.move(pl, pm12.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); + //TEST(res); + //capAlloc.freeEmpty(pm12.cap()); - res = myCS.move(pl, pm13.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm13.cap()); + //res = myCS.move(pl, pm13.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); + //TEST(res); + //capAlloc.freeEmpty(pm13.cap()); - res = myCS.move(pl, pm14.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm14.cap()); + //res = myCS.move(pl, pm14.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); + //TEST(res); + //capAlloc.freeEmpty(pm14.cap()); - res = myCS.move(pl, pm15.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm15.cap()); + //res = myCS.move(pl, pm15.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); + //TEST(res); + //capAlloc.freeEmpty(pm15.cap()); - res = myCS.move(pl, pm16.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm16.cap()); + //res = myCS.move(pl, pm16.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); + //TEST(res); + //capAlloc.freeEmpty(pm16.cap()); - res = myCS.move(pl, pm17.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm17.cap()); + //res = myCS.move(pl, pm17.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); + //TEST(res); + //capAlloc.freeEmpty(pm17.cap()); - res = myCS.move(pl, pm4.cap(), max_cap_depth, cs.cap(), init::PML4, max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm4.cap()); + //res = myCS.move(pl, pm4.cap(), max_cap_depth, cs.cap(), init::PML4, max_cap_depth).wait(); + //TEST(res); + //capAlloc.freeEmpty(pm4.cap()); /* wake EC */ MLOG_DETAIL(mlog::app, "start process ..."); - MLOG_DETAIL(mlog::app, " move EC"); - res = myCS.move(pl, ec.cap(), max_cap_depth, cs.cap(), init::EC, max_cap_depth).wait(); - TEST(res); + //MLOG_DETAIL(mlog::app, " move EC"); + //res = myCS.move(pl, ec.cap(), max_cap_depth, cs.cap(), init::EC, max_cap_depth).wait(); + //TEST(res); MLOG_DETAIL(mlog::app, " create reference"); res = cs.reference(pl, init::EC, max_cap_depth, init::CSPACE, ec.cap(), max_cap_depth, 0).wait(); From e2025a81e201f97330c878d39d4f504dbb5ead89 Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Tue, 2 Mar 2021 11:50:51 +0100 Subject: [PATCH 28/42] worked on many things --- kernel/app/init-example/app/init.cc | 5 +- .../process_test/process_test/process_test.cc | 22 +- .../boot/apboot-common/boot/DeployHWThread.hh | 2 + kernel/mythos/infoFrame/mythos/InfoFrame.hh | 10 + kernel/mythos/init/mythos/init.hh | 1 + .../memory-amd64/objects/PageMapAmd64.cc | 2 +- .../thread-team/objects/PluginThreadTeam.hh | 2 +- kernel/runtime/cxx/runtime/cxxsupport.cc | 15 +- kernel/runtime/kobject/runtime/CapMap.hh | 4 +- kernel/runtime/process/mcconf.module | 1 + kernel/runtime/process/runtime/process.cc | 3 + kernel/runtime/process/runtime/process.hh | 294 ++++++++++-------- 12 files changed, 218 insertions(+), 143 deletions(-) create mode 100644 kernel/runtime/process/runtime/process.cc diff --git a/kernel/app/init-example/app/init.cc b/kernel/app/init-example/app/init.cc index 54228e1e..bff8db6b 100644 --- a/kernel/app/init-example/app/init.cc +++ b/kernel/app/init-example/app/init.cc @@ -554,6 +554,7 @@ void test_process(){ Process p(&process_test_image_start); p.createProcess(pl); + p.join(pl); MLOG_INFO(mlog::app, "Test process finished"); } @@ -575,8 +576,8 @@ int main() //test_ExecutionContext(); //test_pthreads(); //test_Rapl(); - test_TBB(); - //test_process(); + //test_TBB(); + test_process(); //test_CgaScreen(); char const end[] = "bye, cruel world!"; diff --git a/kernel/app/process_test/process_test/process_test.cc b/kernel/app/process_test/process_test/process_test.cc index bd8b784a..d95e3544 100644 --- a/kernel/app/process_test/process_test/process_test.cc +++ b/kernel/app/process_test/process_test/process_test.cc @@ -41,8 +41,11 @@ #include "runtime/InterruptControl.hh" #include #include "util/optional.hh" +#include "util/align.hh" #include "runtime/umem.hh" #include "runtime/Mutex.hh" +#include "runtime/thread-extra.hh" +#include "mythos/caps.hh" mythos::InfoFrame* info_ptr asm("info_ptr"); @@ -66,8 +69,25 @@ mythos::ThreadTeam team(mythos::init::THREAD_TEAM); int main() { - MLOG_ERROR(mlog::app, "New process started :)"); + MLOG_ERROR(mlog::app, "New process started :)", DVAR(sizeof(mythos::InfoFrame)), DVAR(mythos_get_pthread_ec_self())); + MLOG_INFO(mlog::app, "info frame", DVARhex(info_ptr), DVAR(info_ptr->getNumThreads()), DVAR(info_ptr->getPsPerTSC())); + mythos::PortalLock pl(portal); + auto size = 32*1024*1024; // 2 MB + auto align = 2*1024*1024; // 2 MB + uintptr_t vaddr = mythos::round_up(info_ptr->getInfoEnd() + mythos::align2M, mythos::align2M); + // allocate a 2MiB frame + mythos::Frame f(capAlloc()); + auto res2 = f.create(pl, kmem, size, align).wait(); + TEST(res2); + // map the frame into our address space + auto res3 = myAS.mmap(pl, f, vaddr, size, 0x1).wait(); + TEST(res3); + MLOG_INFO(mlog::app, "mmap frame", DVAR(res3.state()), + DVARhex(res3->vaddr), DVAR(res3->level)); + mythos::heap.addRange(vaddr, size); + + MLOG_ERROR(mlog::app, "process finished :("); return 0; } diff --git a/kernel/boot/apboot-common/boot/DeployHWThread.hh b/kernel/boot/apboot-common/boot/DeployHWThread.hh index 946fc25c..e5be3b3f 100644 --- a/kernel/boot/apboot-common/boot/DeployHWThread.hh +++ b/kernel/boot/apboot-common/boot/DeployHWThread.hh @@ -38,6 +38,7 @@ #include "cpu/idle.hh" #include "async/Place.hh" #include "objects/DeleteBroadcast.hh" +#include "objects/PML4InvalidationBroadcastAmd64.hh" #include "objects/SchedulingContext.hh" #include "objects/InterruptControl.hh" #include "boot/memory-layout.h" @@ -78,6 +79,7 @@ struct DeployHWThread { idt.init(); DeleteBroadcast::init(); // depends on hwthread enumeration + PML4InvalidationBroadcast::init(); // depends on hwthread enumeration } void prepare(cpu::ThreadID threadID, cpu::ApicID apicID) diff --git a/kernel/mythos/infoFrame/mythos/InfoFrame.hh b/kernel/mythos/infoFrame/mythos/InfoFrame.hh index 28ffcb28..1440ded8 100644 --- a/kernel/mythos/infoFrame/mythos/InfoFrame.hh +++ b/kernel/mythos/infoFrame/mythos/InfoFrame.hh @@ -27,6 +27,7 @@ #include "mythos/InvocationBuf.hh" #include "mythos/init.hh" +#include namespace mythos { @@ -38,6 +39,8 @@ class InfoFrame{ InfoFrame() : psPerTsc(PS_PER_TSC_DEFAULT) , numThreads(1) + , parentEC(0) + , running(true) {} InvocationBuf* getInvocationBuf() {return &ib[0]; } @@ -49,10 +52,17 @@ class InfoFrame{ uint64_t getPsPerTSC() { return psPerTsc; } size_t getNumThreads() { return numThreads; } uintptr_t getInfoEnd () { return reinterpret_cast(this) + sizeof(InfoFrame); } + // process synchronization + void setParent(CapPtr ptr) { parentEC.store(ptr); } + CapPtr getParent() { return parentEC.load(); } + bool isRunning() { return running.load(); } + void setRunning(bool running) { this->running.store(running); } InvocationBuf ib[MAX_IB]; // needs to be the first member (see Initloader::createPortal) uint64_t psPerTsc; // picoseconds per time stamp counter size_t numThreads; // number of hardware threads available in the system + std::atomic parentEC; + std::atomic running; // process not finished }; } // namespace mythos diff --git a/kernel/mythos/init/mythos/init.hh b/kernel/mythos/init/mythos/init.hh index 6878c419..766ae9fd 100644 --- a/kernel/mythos/init/mythos/init.hh +++ b/kernel/mythos/init/mythos/init.hh @@ -38,6 +38,7 @@ namespace init { CSPACE, PML4, EC, + PARENT_EC, //ec of parent process PORTAL, EXAMPLE_FACTORY, MEMORY_REGION_FACTORY, diff --git a/kernel/objects/memory-amd64/objects/PageMapAmd64.cc b/kernel/objects/memory-amd64/objects/PageMapAmd64.cc index a3d88dbb..ba52a250 100644 --- a/kernel/objects/memory-amd64/objects/PageMapAmd64.cc +++ b/kernel/objects/memory-amd64/objects/PageMapAmd64.cc @@ -383,7 +383,7 @@ namespace mythos { auto res = visitTables(&_pm_table(0), level(), op); *failaddr = op.failaddr; *faillevel = op.current_level; - RETHROW(res.state()); + RETURN(res.state()); } Error PageMap::invokeInstallMap(Tasklet*, Cap self, IInvocation* msg) diff --git a/kernel/objects/thread-team/objects/PluginThreadTeam.hh b/kernel/objects/thread-team/objects/PluginThreadTeam.hh index 3b03313e..c71df33a 100644 --- a/kernel/objects/thread-team/objects/PluginThreadTeam.hh +++ b/kernel/objects/thread-team/objects/PluginThreadTeam.hh @@ -48,7 +48,7 @@ namespace factory { virtual ~PluginThreadTeamActivator() {} void processEvent(boot::InitLoader& loader) override { - MLOG_ERROR(mlog::pm, "prevent mapping of all scheduling contexts into CSpace"); + MLOG_INFO(mlog::pm, "prevent mapping of all scheduling contexts into CSpace"); loader.mapSchedulingContexts = false; } diff --git a/kernel/runtime/cxx/runtime/cxxsupport.cc b/kernel/runtime/cxx/runtime/cxxsupport.cc index e4d95f68..63b0854c 100644 --- a/kernel/runtime/cxx/runtime/cxxsupport.cc +++ b/kernel/runtime/cxx/runtime/cxxsupport.cc @@ -55,7 +55,9 @@ #include "runtime/thread-extra.hh" #include "runtime/ThreadTeam.hh" #include "runtime/Mutex.hh" +#include "runtime/process.hh" #include "util/optional.hh" +#include "util/events.hh" #include "mythos/InfoFrame.hh" extern mythos::InfoFrame* info_ptr asm("info_ptr"); @@ -182,6 +184,8 @@ extern "C" [[noreturn]] void __assert_fail (const char *expr, const char *file, mythos::syscall_exit(-1); /// @TODO syscall_abort(); to see some stack backtrace etc } +mythos::Event<> groupExit; + void mythosExit(){ //todo: ASSERT(myEC == init::EC) @@ -189,12 +193,9 @@ void mythosExit(){ mythos::PortalLock pl(localPortal); MLOG_ERROR(mlog::app, "Free all dynamically allocated Caps"); capAlloc.freeAll(pl); - MLOG_ERROR(mlog::app, "Free Thread Team"); - myCS.deleteCap(pl, mythos::init::THREAD_TEAM).wait(); - //MLOG_ERROR(mlog::app, "Free init EC"); - //myCS.deleteCap(pl, mythos::init::EC).wait(); - //myCS.deleteCap(pl, mythos::init::CSPACE).wait(); - //should never return + + MLOG_ERROR(mlog::app, "notify parent process"); + groupExit.emit(); MLOG_ERROR(mlog::app, "MYTHOS:PLEASE KILL ME!!!!!!1 elf"); } @@ -328,7 +329,7 @@ extern "C" long mythos_musl_syscall( return 0; case 231: // exit_group for all pthreads MLOG_WARN(mlog::app, "syscall exit_group "); - mythosExit(); + mythosExit(); return 0; case 302: // prlimit64 //MLOG_WARN(mlog::app, "syscall prlimit64 NYI", DVAR(a1), DVAR(a2), DVAR(a3), DVAR(a4), DVAR(a5), DVAR(a6)); diff --git a/kernel/runtime/kobject/runtime/CapMap.hh b/kernel/runtime/kobject/runtime/CapMap.hh index 945e9edf..a42552fd 100644 --- a/kernel/runtime/kobject/runtime/CapMap.hh +++ b/kernel/runtime/kobject/runtime/CapMap.hh @@ -47,13 +47,13 @@ namespace mythos { PortalFuture derive(PortalLock pr, CapPtr src, CapPtrDepth srcDepth, CapPtr dstCs, CapPtr dst, CapPtrDepth dstDepth, - CapRequest req) { + CapRequest req = 1) { return pr.invoke(_cap, src, srcDepth, dstCs, dst, dstDepth, req); } PortalFuture reference(PortalLock pr, CapPtr src, CapPtrDepth srcDepth, CapPtr dstCs, CapPtr dst, CapPtrDepth dstDepth, - CapRequest req) { + CapRequest req = 1) { return pr.invoke(_cap, src, srcDepth, dstCs, dst, dstDepth, req); } diff --git a/kernel/runtime/process/mcconf.module b/kernel/runtime/process/mcconf.module index 5fb45292..1b1e4ef5 100644 --- a/kernel/runtime/process/mcconf.module +++ b/kernel/runtime/process/mcconf.module @@ -1,3 +1,4 @@ # -*- mode:toml; -*- [module.process] incfiles = [ "runtime/process.hh" ] + appfiles = [ "runtime/process.cc" ] diff --git a/kernel/runtime/process/runtime/process.cc b/kernel/runtime/process/runtime/process.cc new file mode 100644 index 00000000..189886c0 --- /dev/null +++ b/kernel/runtime/process/runtime/process.cc @@ -0,0 +1,3 @@ +#include "runtime/process.hh" + +ProcessExitEvent processExitEvent; diff --git a/kernel/runtime/process/runtime/process.hh b/kernel/runtime/process/runtime/process.hh index cdcc989f..9a50f26f 100644 --- a/kernel/runtime/process/runtime/process.hh +++ b/kernel/runtime/process/runtime/process.hh @@ -7,9 +7,13 @@ #include "util/optional.hh" #include "util/elf64.hh" #include "util/align.hh" +#include "util/events.hh" #include "mythos/InfoFrame.hh" #include "runtime/CapAlloc.hh" #include "runtime/ThreadTeam.hh" +#include "runtime/thread-extra.hh" +#include "mythos/syscall.hh" +#include extern mythos::InfoFrame* info_ptr asm("info_ptr"); extern mythos::CapMap myCS; @@ -17,16 +21,75 @@ extern mythos::PageMap myAS; extern mythos::KernelMemory kmem; extern mythos::ThreadTeam team; +class ProcessExitEvent; +extern mythos::Event<> groupExit; +extern ProcessExitEvent processExitEvent; + using namespace mythos; +class ProcessExitEvent : public EventHook<> { + public: + ProcessExitEvent(){ + groupExit.add(this); + } + + void processEvent() override { + MLOG_ERROR(mlog::app, __PRETTY_FUNCTION__); + info_ptr->setRunning(false); + auto parent = info_ptr->getParent(); + if(parent != null_cap){ + mythos::syscall_signal(parent); + } + } +}; + class Process{ public: Process(char* image) : cs(capAlloc()) , pCapAlloc(cs) , img(image) + , pInfoFrame(nullptr) + , parent(mythos_get_pthread_ec_self()) {} + void wait(){ + MLOG_DETAIL(mlog::app, __PRETTY_FUNCTION__); + if(pInfoFrame){ + if(pInfoFrame->isRunning()){ + ASSERT(parent == mythos_get_pthread_ec_self()); + //pInfoFrame->setParent(parent); + pInfoFrame->setParent(init::PARENT_EC); + while(pInfoFrame->isRunning()){ + mythos_wait(); + } + pInfoFrame->setParent(null_cap); + } + } + MLOG_DETAIL(mlog::app, "wait return"); + } + + void remove(PortalLock& pl){ + MLOG_ERROR(mlog::app, __PRETTY_FUNCTION__); + pInfoFrame = nullptr; + MLOG_ERROR(mlog::app, "free capmap"); + capAlloc.free(cs, pl); + MLOG_ERROR(mlog::app, "free dynamically allocated caps in own CS"); + for (std::vector::reverse_iterator i = caps.rbegin(); + i != caps.rend(); ++i ) { + MLOG_ERROR(mlog::app, DVAR(*i)); + capAlloc.free(*i, pl); + } + caps.clear(); + } + + void join(PortalLock& pl){ + wait(); + remove(pl); + } + + ~Process(){} + optional loadProgramHeader(PortalLock& pl, const elf64::PHeader* ph, uintptr_t tmp_vaddr, Frame& f, size_t offset, PageMap& pm) { @@ -46,7 +109,7 @@ class Process{ mf.executable = ph->flags&elf64::PF_X; MLOG_DETAIL(mlog::app, "... mmap program header", DVARhex(vbegin), DVARhex(vend), DVARhex(offset)); auto res = pm.mmap(pl, f, vbegin, vend-vbegin, mf, offset); - TEST(res); + ASSERT(res); // zero the pages, then copy the data MLOG_DETAIL(mlog::app, " zeroing", DVARhex(tmp_vaddr + offset), DVARhex(vend-vbegin)); @@ -81,28 +144,29 @@ class Process{ MLOG_DETAIL(mlog::app, "allocate frame for application image ...") Frame f(capAlloc()); auto res = f.create(pl, kmem, 2*size, align2M).wait(); + caps.push_back(f.cap()); uintptr_t tmp_vaddr = 42*align512G; MLOG_DETAIL(mlog::app, "temporary map frame to own address space ...", DVARhex(tmp_vaddr)); MLOG_DETAIL(mlog::app, " create PageMap"); PageMap pm3(capAlloc()); res = pm3.create(pl, kmem, 3).wait(); - TEST(res); + ASSERT(res); PageMap pm2(capAlloc()); res = pm2.create(pl, kmem, 2).wait(); - TEST(res); + ASSERT(res); MLOG_DETAIL(mlog::app, " installMap"); res = myAS.installMap(pl, pm3, ((tmp_vaddr >> 39) & 0x1FF)<< 39, 4, protocol::PageMap::MapFlags().writable(true).configurable(true)).wait(); - TEST(res); + ASSERT(res); res = pm3.installMap(pl, pm2, ((tmp_vaddr >> 30) & 0x1FF) << 30, 3, protocol::PageMap::MapFlags().writable(true).configurable(true)).wait(); - TEST(res); + ASSERT(res); MLOG_DETAIL(mlog::app, " mmap"); res = myAS.mmap(pl, f, tmp_vaddr, size, 0x1).wait(); - TEST(res); + ASSERT(res); // 3) process each program header: map to page, copy contents size_t offset = 0; @@ -121,22 +185,21 @@ class Process{ MLOG_DETAIL(mlog::app, "cleaning up ..."); MLOG_DETAIL(mlog::app, " unmap frame"); res = myAS.munmap(pl, tmp_vaddr, size).wait(); - TEST(res); + ASSERT(res); MLOG_DETAIL(mlog::app, " remove maps"); res = myAS.removeMap(pl, tmp_vaddr, 2).wait(); - TEST(res); + ASSERT(res); res = myAS.removeMap(pl, tmp_vaddr, 3).wait(); - TEST(res); + ASSERT(res); MLOG_DETAIL(mlog::app, " move frame"); - res = myCS.move(pl, f.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(f.cap()); + res = myCS.reference(pl, f.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); + ASSERT(res); MLOG_DETAIL(mlog::app, " delete tables"); - capAlloc.free(pm3, pl); - capAlloc.free(pm2, pl); + capAlloc.free(pm3.cap(), pl); + capAlloc.free(pm2.cap(), pl); return ipc_addr; } @@ -147,34 +210,37 @@ class Process{ /* create CapMap */ MLOG_DETAIL(mlog::app, "create CapMap ..."); auto res = cs.create(pl, kmem, CapPtrDepth(12), CapPtrDepth(20), CapPtr(0)).wait(); - TEST(res); + ASSERT(res); + MLOG_DETAIL(mlog::app, "set CapMap reference..."); + res = myCS.reference(pl, cs.cap(), max_cap_depth, cs.cap(), init::CSPACE, max_cap_depth, 1).wait(); + ASSERT(res); - /* copy relevant caps */ + //copy relevant caps MLOG_DETAIL(mlog::app, "copy relevant Caps ..."); MLOG_DETAIL(mlog::app, " kernel memory"); - res = myCS.reference(pl, init::KM, max_cap_depth, cs.cap(), init::KM, max_cap_depth, 0).wait(); - TEST(res); + res = myCS.reference(pl, init::KM, max_cap_depth, cs.cap(), init::KM, max_cap_depth, 1).wait(); + ASSERT(res); MLOG_DETAIL(mlog::app, " factories"); for(CapPtr ptr = init::EXAMPLE_FACTORY; ptr <= init::UNTYPED_MEMORY_FACTORY; ptr++){ - res = myCS.reference(pl, ptr, max_cap_depth, cs.cap(), ptr, max_cap_depth, 0).wait(); - TEST(res); + res = myCS.reference(pl, ptr, max_cap_depth, cs.cap(), ptr, max_cap_depth).wait(); + ASSERT(res); } - + MLOG_DETAIL(mlog::app, " DEVICE_MEMORY"); res = myCS.reference(pl, init::DEVICE_MEM, max_cap_depth, cs.cap(), init::DEVICE_MEM, max_cap_depth, 0).wait(); - TEST(res); + ASSERT(res); MLOG_DETAIL(mlog::app, " RAPL driver"); res = myCS.reference(pl, init::RAPL_DRIVER_INTEL, max_cap_depth, cs.cap(), init::RAPL_DRIVER_INTEL, max_cap_depth, 0).wait(); - TEST(res); + ASSERT(res); MLOG_DETAIL(mlog::app, " Interrupt control"); MLOG_WARN(mlog::app, "SKIP: Interrupt control caps!"); //todo: how to check whether cap is existing? //for(CapPtr ptr = init::INTERRUPT_CONTROL_START; ptr < init::INTERRUPT_CONTROL_END; ptr++){ //res = myCS.reference(pl, ptr, max_cap_depth, cs.cap(), ptr, max_cap_depth, 0).wait(); - //TEST(res); + //ASSERT(res); //} /* create address space */ @@ -184,38 +250,57 @@ class Process{ // create tables PageMap pm4(capAlloc()); + caps.push_back(pm4.cap()); auto res_pm = pm4.create(pl, kmem, 4).wait(); - TEST(res_pm); + ASSERT(res_pm); PageMap pm3(capAlloc()); + caps.push_back(pm3.cap()); res_pm = pm3.create(pl, kmem, 3).wait(); - TEST(res_pm); + ASSERT(res_pm); PageMap pm2(capAlloc()); + caps.push_back(pm2.cap()); res_pm = pm2.create(pl, kmem, 2).wait(); - TEST(res_pm); + ASSERT(res_pm); PageMap pm10(capAlloc()); + caps.push_back(pm10.cap()); res_pm = pm10.create(pl, kmem, 1).wait(); - TEST(res_pm); + ASSERT(res_pm); PageMap pm11(capAlloc()); + caps.push_back(pm11.cap()); res_pm = pm11.create(pl, kmem, 1).wait(); - TEST(res_pm); + ASSERT(res_pm); PageMap pm12(capAlloc()); + caps.push_back(pm12.cap()); res_pm = pm12.create(pl, kmem, 1).wait(); - TEST(res_pm); + ASSERT(res_pm); PageMap pm13(capAlloc()); + caps.push_back(pm13.cap()); res_pm = pm13.create(pl, kmem, 1).wait(); - TEST(res_pm); + ASSERT(res_pm); PageMap pm14(capAlloc()); + caps.push_back(pm14.cap()); res_pm = pm14.create(pl, kmem, 1).wait(); - TEST(res_pm); + ASSERT(res_pm); PageMap pm15(capAlloc()); + caps.push_back(pm15.cap()); res_pm = pm15.create(pl, kmem, 1).wait(); - TEST(res_pm); + ASSERT(res_pm); PageMap pm16(capAlloc()); + caps.push_back(pm16.cap()); res_pm = pm16.create(pl, kmem, 1).wait(); - TEST(res_pm); + ASSERT(res_pm); PageMap pm17(capAlloc()); + caps.push_back(pm17.cap()); res_pm = pm17.create(pl, kmem, 1).wait(); - TEST(res_pm); + ASSERT(res_pm); + PageMap pm18(capAlloc()); + caps.push_back(pm18.cap()); + res_pm = pm18.create(pl, kmem, 1).wait(); + ASSERT(res_pm); + PageMap pm19(capAlloc()); + caps.push_back(pm19.cap()); + res_pm = pm19.create(pl, kmem, 1).wait(); + ASSERT(res_pm); // install tables pm4.installMap(pl, pm3, ((elf_vaddr >> 39) & 0x1FF) << 39, 4, @@ -238,59 +323,60 @@ class Process{ mythos::protocol::PageMap::MapFlags().writable(true).configurable(true)).wait(); pm2.installMap(pl, pm17, ((elf_vaddr >> 21) & 0x1FF) + 7 << 21, 2, mythos::protocol::PageMap::MapFlags().writable(true).configurable(true)).wait(); + pm2.installMap(pl, pm18, ((elf_vaddr >> 21) & 0x1FF) + 8 << 21, 2, + mythos::protocol::PageMap::MapFlags().writable(true).configurable(true)).wait(); + pm2.installMap(pl, pm19, ((elf_vaddr >> 21) & 0x1FF) + 9 << 21, 2, + mythos::protocol::PageMap::MapFlags().writable(true).configurable(true)).wait(); /* load image */ auto ipc_vaddr = loadImage(pl, pm4); - TEST(ipc_vaddr); + ASSERT(ipc_vaddr); /* create InfoFrame */ MLOG_DETAIL(mlog::app, "create InfoFrame ..."); auto size = round_up(sizeof(InfoFrame), align2M); - MLOG_DETAIL(mlog::app, " create frame", DVAR(size)); + MLOG_DETAIL(mlog::app, " create frame"); Frame iFrame(capAlloc()); + caps.push_back(iFrame.cap()); res = iFrame.create(pl, kmem, size, align2M).wait(); - TEST(res); - MLOG_DETAIL(mlog::app, " map frame to target page map", DVARhex(size), DVARhex(*ipc_vaddr)); - res = pm4.mmap(pl, iFrame, *ipc_vaddr, align2M, 0x1).wait(); - TEST(res); + ASSERT(res); + res = myCS.reference(pl, iFrame.cap(), max_cap_depth, cs.cap(), init::INFO_FRAME, max_cap_depth, 0).wait(); + ASSERT(res); + MLOG_WARN(mlog::app, " map frame to target page map", DVARhex(size), DVARhex(*ipc_vaddr)); + res = pm4.mmap(pl, iFrame, *ipc_vaddr, size, 0x1).wait(); + ASSERT(res); uintptr_t tmp_vaddr_if = 11*align512G; MLOG_DETAIL(mlog::app, " temporally map frame to own page map", DVARhex(tmp_vaddr_if)); PageMap pm3if(capAlloc()); + caps.push_back(pm3if.cap()); res = pm3if.create(pl, kmem, 3).wait(); - TEST(res); + ASSERT(res); PageMap pm2if(capAlloc()); + caps.push_back(pm2if.cap()); res = pm2if.create(pl, kmem, 2).wait(); - TEST(res); + ASSERT(res); MLOG_DETAIL(mlog::app, " installMap"); res = myAS.installMap(pl, pm3if, ((tmp_vaddr_if >> 39) & 0x1FF)<< 39, 4, protocol::PageMap::MapFlags().writable(true).configurable(true)).wait(); - TEST(res); + ASSERT(res); res = pm3if.installMap(pl, pm2if, ((tmp_vaddr_if >> 30) & 0x1FF) << 30, 3, protocol::PageMap::MapFlags().writable(true).configurable(true)).wait(); - TEST(res); + ASSERT(res); MLOG_DETAIL(mlog::app, " mmap"); res = myAS.mmap(pl, iFrame, tmp_vaddr_if, size, 0x1).wait(); - TEST(res); + ASSERT(res); MLOG_DETAIL(mlog::app, " copy info frame content"); mythos::memcpy(reinterpret_cast(tmp_vaddr_if), info_ptr, sizeof(InfoFrame)); - MLOG_DETAIL(mlog::app, " unmap"); - res = myAS.munmap(pl, tmp_vaddr_if, size).wait(); - TEST(res); - - MLOG_DETAIL(mlog::app, " remove maps"); - res = myAS.removeMap(pl, tmp_vaddr_if, 2).wait(); - TEST(res); - res = myAS.removeMap(pl, tmp_vaddr_if, 3).wait(); - TEST(res); - - MLOG_DETAIL(mlog::app, " delete tables"); - capAlloc.free(pm3if, pl); - capAlloc.free(pm2if, pl); + pInfoFrame = reinterpret_cast(tmp_vaddr_if); + pInfoFrame->setRunning(true); + pInfoFrame->setParent(null_cap); + res = myCS.reference(pl, parent, max_cap_depth, cs.cap(), init::PARENT_EC, max_cap_depth).wait(); + ASSERT(res); /* create EC */ MLOG_DETAIL(mlog::app, "create EC ...", DVARhex(img.header()->entry)); @@ -299,19 +385,20 @@ class Process{ .rawFun(reinterpret_cast(img.header()->entry), reinterpret_cast(*ipc_vaddr)) .suspended(true) .invokeVia(pl).wait(); - TEST(res); + caps.push_back(ec.cap()); + ASSERT(res); /* create ThreadTeam */ MLOG_DETAIL(mlog::app, "create ThreadTeam ..."); ThreadTeam tt(capAlloc()); res = tt.create(pl, kmem, init::PROCESSOR_ALLOCATOR).wait(); - TEST(res); + caps.push_back(tt.cap()); + ASSERT(res); MLOG_DETAIL(mlog::app, " register EC in ThreadTeam"); res = tt.tryRunEC(pl, ec).wait(); - TEST(res); - res = myCS.move(pl, tt.cap(), max_cap_depth, cs.cap(), init::THREAD_TEAM, max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(tt.cap()); + ASSERT(res); + res = myCS.reference(pl, tt.cap(), max_cap_depth, cs.cap(), init::THREAD_TEAM, max_cap_depth).wait(); + ASSERT(res); /* create portal */ MLOG_DETAIL(mlog::app, "create Portal ..."); @@ -320,82 +407,28 @@ class Process{ MLOG_DETAIL(mlog::app, " create"); Portal port(capAlloc(), reinterpret_cast(*ipc_vaddr)); res = port.create(pl, kmem).wait(); - TEST(res); + caps.push_back(port.cap()); + ASSERT(res); res = port.bind(pl, iFrame, 0, ec.cap()).wait(); - TEST(res); + ASSERT(res); MLOG_DETAIL(mlog::app, " move Portal"); - res = myCS.move(pl, port.cap(), max_cap_depth, cs.cap(), init::PORTAL, max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(port.cap()); + res = myCS.reference(pl, port.cap(), max_cap_depth, cs.cap(), init::PORTAL, max_cap_depth).wait(); + ASSERT(res); - MLOG_DETAIL(mlog::app, " move info frame"); - res = myCS.move(pl, iFrame.cap(), max_cap_depth, cs.cap(), init::INFO_FRAME, max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(iFrame.cap()); - /* move tables */ - MLOG_DETAIL(mlog::app, "move tables ..."); - res = myCS.move(pl, pm3.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm3.cap()); - - res = myCS.move(pl, pm2.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm2.cap()); - - res = myCS.move(pl, pm10.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm10.cap()); - - res = myCS.move(pl, pm11.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm11.cap()); - - res = myCS.move(pl, pm12.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm12.cap()); - - res = myCS.move(pl, pm13.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm13.cap()); - - res = myCS.move(pl, pm14.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm14.cap()); - - res = myCS.move(pl, pm15.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm15.cap()); - - res = myCS.move(pl, pm16.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm16.cap()); - - res = myCS.move(pl, pm17.cap(), max_cap_depth, cs.cap(), pCapAlloc(), max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm17.cap()); - - res = myCS.move(pl, pm4.cap(), max_cap_depth, cs.cap(), init::PML4, max_cap_depth).wait(); - TEST(res); - capAlloc.freeEmpty(pm4.cap()); + MLOG_DETAIL(mlog::app, "reference pm4 ..."); + res = myCS.reference(pl, pm4.cap(), max_cap_depth, cs.cap(), init::PML4, max_cap_depth).wait(); /* wake EC */ MLOG_DETAIL(mlog::app, "start process ..."); MLOG_DETAIL(mlog::app, " move EC"); - res = myCS.move(pl, ec.cap(), max_cap_depth, cs.cap(), init::EC, max_cap_depth).wait(); - TEST(res); - - MLOG_DETAIL(mlog::app, " create reference"); - res = cs.reference(pl, init::EC, max_cap_depth, init::CSPACE, ec.cap(), max_cap_depth, 0).wait(); - TEST(res); + res = myCS.reference(pl, ec.cap(), max_cap_depth, cs.cap(), init::EC, max_cap_depth).wait(); + ASSERT(res); MLOG_DETAIL(mlog::app, " wake EC"); res = ec.resume(pl).wait(); - TEST(res); - - MLOG_DETAIL(mlog::app, " remove EC"); - capAlloc.free(ec.cap(), pl); + ASSERT(res); return cs.cap(); } @@ -405,6 +438,9 @@ class Process{ SimpleCapAlloc pCapAlloc; elf64::Elf64Image img; + InfoFrame* pInfoFrame; + CapPtr parent; + std::vector caps; }; From ba316b2ff77b9240ed1f97cb5a1d764412a19d7d Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Tue, 2 Mar 2021 12:08:08 +0100 Subject: [PATCH 29/42] fixed process --- kernel/runtime/process/runtime/process.hh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/kernel/runtime/process/runtime/process.hh b/kernel/runtime/process/runtime/process.hh index a8cbaf76..8de78f79 100644 --- a/kernel/runtime/process/runtime/process.hh +++ b/kernel/runtime/process/runtime/process.hh @@ -58,7 +58,6 @@ class Process{ if(pInfoFrame){ if(pInfoFrame->isRunning()){ ASSERT(parent == mythos_get_pthread_ec_self()); - //pInfoFrame->setParent(parent); pInfoFrame->setParent(init::PARENT_EC); while(pInfoFrame->isRunning()){ mythos_wait(); @@ -72,8 +71,6 @@ class Process{ void remove(PortalLock& pl){ MLOG_ERROR(mlog::app, __PRETTY_FUNCTION__); pInfoFrame = nullptr; - MLOG_ERROR(mlog::app, "free capmap"); - capAlloc.free(cs, pl); MLOG_ERROR(mlog::app, "free dynamically allocated caps in own CS"); for (std::vector::reverse_iterator i = caps.rbegin(); i != caps.rend(); ++i ) { @@ -81,6 +78,8 @@ class Process{ capAlloc.free(*i, pl); } caps.clear(); + MLOG_ERROR(mlog::app, "free capmap"); + capAlloc.free(cs, pl); } void join(PortalLock& pl){ @@ -206,8 +205,7 @@ class Process{ optional createProcess(PortalLock& pl){ MLOG_INFO(mlog::app, __func__); - MLOG_ERROR(mlog::app, "process needs to be reworked!"); - return 0; + /* create CapMap */ MLOG_DETAIL(mlog::app, "create CapMap ..."); auto res = cs.create(pl, kmem, CapPtrDepth(12), CapPtrDepth(20), CapPtr(0)).wait(); From 21e6d93ab7317acb8b67054cd39397ec9f53125b Mon Sep 17 00:00:00 2001 From: Robert Kuban Date: Tue, 2 Mar 2021 13:10:10 +0100 Subject: [PATCH 30/42] updates try_lock code. --- .../capability-spinning/objects/CapEntry.cc | 22 +++++++++---------- .../capability-spinning/objects/CapEntry.hh | 21 +++++++++++++----- .../objects/RevokeOperation.cc | 2 +- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/kernel/objects/capability-spinning/objects/CapEntry.cc b/kernel/objects/capability-spinning/objects/CapEntry.cc index 363ff9a7..feb723db 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.cc +++ b/kernel/objects/capability-spinning/objects/CapEntry.cc @@ -137,11 +137,15 @@ namespace mythos { return true; } - bool CapEntry::kill(Cap expected) + // fails if cap was changed concurrently + bool CapEntry::try_kill(Cap expected) { CapValue expectedValue = expected.value(); - MLOG_DETAIL(mlog::cap, this, ".kill", DVAR(expected)); - return _cap.compare_exchange_strong(expectedValue, expected.asZombie().value()); + MLOG_DETAIL(mlog::cap, this, ".try_kill", DVAR(expected)); + if (!_cap.compare_exchange_strong(expectedValue, expected.asZombie().value())) { + // if the cap was just zombified by sb. else, thats okay + return (Cap(expectedValue).asZombie() == expected.asZombie()); + } else return true; } @@ -166,15 +170,9 @@ namespace mythos { if (!prev) { return Error::GENERIC_ERROR; } - if (prev->try_lock_next()) { - if (Link(_prev.load()).ptr() == prev) { - return Error::SUCCESS; - } else { // my _prev has changed in the mean time - MLOG_ERROR(mlog::cap, "this unlocks prev"); - prev->unlock_next(); - return Error::RETRY; - } - } else return Error::RETRY; + auto success = prev->try_lock_next(this); + ASSERT(Link(_prev.load()).ptr() == prev); + return success ? Error::SUCCESS : Error::RETRY; } bool CapEntry::lock_prev() diff --git a/kernel/objects/capability-spinning/objects/CapEntry.hh b/kernel/objects/capability-spinning/objects/CapEntry.hh index c0eba6b6..f8539e9f 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.hh +++ b/kernel/objects/capability-spinning/objects/CapEntry.hh @@ -91,19 +91,22 @@ namespace mythos { * allocated. Returns true if zombified. */ bool kill(); - bool kill(Cap expected); + bool try_kill(Cap expected); optional unlinkAndUnlockLinks(); /* lock next functions protect the link to the next CapEntry */ - bool try_lock_next() + bool try_lock_next(CapEntry* next) { - bool ret = !(_next.fetch_or(LOCKED_FLAG) & LOCKED_FLAG); - MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this), ret? " locked" : "locking failed!"); - return ret; + Link expected(next); + uintlink_t expectedValue = expected.value(); + auto ret = _next.compare_exchange_strong(expectedValue, expected.withFlags(LOCKED_FLAG).value()); + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this), ret? " locked" : "locking failed!"); + return ret; } + void lock_next() { int loop = 0; @@ -182,6 +185,14 @@ namespace mythos { // called by move and insertAfter void setPrevPreserveFlags(CapEntry* ptr); + // called by lock_next + bool try_lock_next() + { + bool ret = !(_next.fetch_or(LOCKED_FLAG) & LOCKED_FLAG); + MLOG_ERROR(mlog::cap, __PRETTY_FUNCTION__, DVAR(this), ret? " locked" : "locking failed!"); + return ret; + } + // lock flag in _next and _prev // _next protects the link to the next entry (lock_next) // _prev protects the capability in the entry from being changed (lock_cap) diff --git a/kernel/objects/capability-spinning/objects/RevokeOperation.cc b/kernel/objects/capability-spinning/objects/RevokeOperation.cc index a2ec3bfe..de63682d 100644 --- a/kernel/objects/capability-spinning/objects/RevokeOperation.cc +++ b/kernel/objects/capability-spinning/objects/RevokeOperation.cc @@ -172,7 +172,7 @@ namespace mythos { hwthread_pause(); } if (cap::isParentOf(*leafEntry, leafCap, *nextEntry, nextCap)) { - if (!nextEntry->kill(nextCap)) { + if (!nextEntry->try_kill(nextCap)) { MLOG_DETAIL(mlog::cap, "cap to be killed changed concurrently"); return false; } From c7c08d788f16b11965f212dc17db2e51000694f5 Mon Sep 17 00:00:00 2001 From: Robert Kuban Date: Tue, 2 Mar 2021 13:15:30 +0100 Subject: [PATCH 31/42] updates comment. --- .../objects/capability-spinning/objects/RevokeOperation.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kernel/objects/capability-spinning/objects/RevokeOperation.cc b/kernel/objects/capability-spinning/objects/RevokeOperation.cc index de63682d..b8580dd9 100644 --- a/kernel/objects/capability-spinning/objects/RevokeOperation.cc +++ b/kernel/objects/capability-spinning/objects/RevokeOperation.cc @@ -143,9 +143,8 @@ namespace mythos { leaf->unlinkAndUnlockLinks(); leaf->reset(); } else { - // deletion failed - // Either tried to delete a portal that is currently deleting - // or tried to to delete _guarded via a recursive call. + // deletion failed in the object specific handler + // this can be also from trying to delete rhw guarded object (currently deleting portal) leaf->unlock_cap(); RETHROW(delRes); } From bf3a5e246de7a8503e0d90ef8335b39e6156835b Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Tue, 2 Mar 2021 21:48:53 +0100 Subject: [PATCH 32/42] fixed race in EC --- kernel/objects/execution-context/objects/ExecutionContext.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/objects/execution-context/objects/ExecutionContext.cc b/kernel/objects/execution-context/objects/ExecutionContext.cc index d3f6325f..ca8e7f6f 100644 --- a/kernel/objects/execution-context/objects/ExecutionContext.cc +++ b/kernel/objects/execution-context/objects/ExecutionContext.cc @@ -428,7 +428,6 @@ namespace mythos { MLOG_INFO(mlog::syscall, "exit"); setFlags(IS_TRAPPED); unsetSchedulingContext(); - saveState(); break; case SYSCALL_POLL: From 1d2d49f0f498825f2eb6e0a4239c1886f40225ae Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Tue, 2 Mar 2021 21:49:09 +0100 Subject: [PATCH 33/42] reworked process --- kernel/runtime/process/runtime/process.hh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/kernel/runtime/process/runtime/process.hh b/kernel/runtime/process/runtime/process.hh index 22e34c90..0b2d9b6e 100644 --- a/kernel/runtime/process/runtime/process.hh +++ b/kernel/runtime/process/runtime/process.hh @@ -211,13 +211,13 @@ class Process{ auto res = cs.create(pl, kmem, CapPtrDepth(12), CapPtrDepth(20), CapPtr(0)).wait(); ASSERT(res); MLOG_DETAIL(mlog::app, "set CapMap reference..."); - res = myCS.reference(pl, cs.cap(), max_cap_depth, cs.cap(), init::CSPACE, max_cap_depth, 1).wait(); + res = myCS.reference(pl, cs.cap(), max_cap_depth, cs.cap(), init::CSPACE, max_cap_depth).wait(); ASSERT(res); //copy relevant caps MLOG_DETAIL(mlog::app, "copy relevant Caps ..."); MLOG_DETAIL(mlog::app, " kernel memory"); - res = myCS.reference(pl, init::KM, max_cap_depth, cs.cap(), init::KM, max_cap_depth, 1).wait(); + res = myCS.reference(pl, init::KM, max_cap_depth, cs.cap(), init::KM, max_cap_depth).wait(); ASSERT(res); MLOG_DETAIL(mlog::app, " factories"); @@ -227,18 +227,18 @@ class Process{ } MLOG_DETAIL(mlog::app, " DEVICE_MEMORY"); - res = myCS.reference(pl, init::DEVICE_MEM, max_cap_depth, cs.cap(), init::DEVICE_MEM, max_cap_depth, 0).wait(); + res = myCS.reference(pl, init::DEVICE_MEM, max_cap_depth, cs.cap(), init::DEVICE_MEM, max_cap_depth).wait(); ASSERT(res); MLOG_DETAIL(mlog::app, " RAPL driver"); - res = myCS.reference(pl, init::RAPL_DRIVER_INTEL, max_cap_depth, cs.cap(), init::RAPL_DRIVER_INTEL, max_cap_depth, 0).wait(); + res = myCS.reference(pl, init::RAPL_DRIVER_INTEL, max_cap_depth, cs.cap(), init::RAPL_DRIVER_INTEL, max_cap_depth).wait(); ASSERT(res); MLOG_DETAIL(mlog::app, " Interrupt control"); MLOG_WARN(mlog::app, "SKIP: Interrupt control caps!"); //todo: how to check whether cap is existing? //for(CapPtr ptr = init::INTERRUPT_CONTROL_START; ptr < init::INTERRUPT_CONTROL_END; ptr++){ - //res = myCS.reference(pl, ptr, max_cap_depth, cs.cap(), ptr, max_cap_depth, 0).wait(); + //res = myCS.reference(pl, ptr, max_cap_depth, cs.cap(), ptr, max_cap_depth).wait(); //ASSERT(res); //} @@ -339,9 +339,9 @@ class Process{ caps.push_back(iFrame.cap()); res = iFrame.create(pl, kmem, size, align2M).wait(); ASSERT(res); - res = myCS.reference(pl, iFrame.cap(), max_cap_depth, cs.cap(), init::INFO_FRAME, max_cap_depth, 0).wait(); + res = myCS.reference(pl, iFrame.cap(), max_cap_depth, cs.cap(), init::INFO_FRAME, max_cap_depth).wait(); ASSERT(res); - MLOG_WARN(mlog::app, " map frame to target page map", DVARhex(size), DVARhex(*ipc_vaddr)); + MLOG_DETAIL(mlog::app, " map frame to target page map", DVARhex(size), DVARhex(*ipc_vaddr)); res = pm4.mmap(pl, iFrame, *ipc_vaddr, size, 0x1).wait(); ASSERT(res); From 327fe1c07f24d8061555d39438f0d321f0c75a0d Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Tue, 2 Mar 2021 21:49:37 +0100 Subject: [PATCH 34/42] PA register teams && free SCs to PA --- .../objects/ProcessorAllocator.cc | 1 + .../objects/ProcessorAllocator.hh | 51 ++++++++++++++++--- .../objects/thread-team/objects/ThreadTeam.cc | 5 +- .../objects/thread-team/objects/ThreadTeam.hh | 1 + 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/kernel/objects/processor-allocator/objects/ProcessorAllocator.cc b/kernel/objects/processor-allocator/objects/ProcessorAllocator.cc index e4e3e07f..39dfc30b 100644 --- a/kernel/objects/processor-allocator/objects/ProcessorAllocator.cc +++ b/kernel/objects/processor-allocator/objects/ProcessorAllocator.cc @@ -45,6 +45,7 @@ namespace mythos { /* ProcessorAllocator */ ProcessorAllocator::ProcessorAllocator() : sc(image2kernel(&mySC[0])) + , nTeams(0) {} void ProcessorAllocator::init(){ diff --git a/kernel/objects/processor-allocator/objects/ProcessorAllocator.hh b/kernel/objects/processor-allocator/objects/ProcessorAllocator.hh index 1f657b80..1d6a4e6a 100644 --- a/kernel/objects/processor-allocator/objects/ProcessorAllocator.hh +++ b/kernel/objects/processor-allocator/objects/ProcessorAllocator.hh @@ -36,6 +36,8 @@ namespace mythos { +class ThreadTeam; + class ProcessorAllocator : public IKernelObject { @@ -57,17 +59,17 @@ class ProcessorAllocator void alloc(Tasklet* t, IResult* r){ monitor.request(t,[=](Tasklet*){ - ASSERT(r); - r->response(t, alloc()); - monitor.responseAndRequestDone(); - }); + ASSERT(r); + r->response(t, alloc()); + monitor.responseAndRequestDone(); + }); } void free(Tasklet* t, cpu::ThreadID id){ monitor.request(t,[=](Tasklet*){ - free(id); - monitor.responseAndRequestDone(); - }); + free(id); + monitor.responseAndRequestDone(); + }); } CapEntry* getSC(cpu::ThreadID id){ @@ -75,11 +77,44 @@ class ProcessorAllocator return &sc[id]; } - protected: + void bind(optional /*tt*/){} + void unbind(optional tt){ + MLOG_INFO(mlog::pm, "unregistered thread team", DVAR(tt)); + ASSERT(tt); + for(unsigned i = 0; i < nTeams; i++){ + auto ti = teamList[i]; + auto t = teamRefs[ti].get(); + if(t && *t == *tt){ + nTeams--; + for(; i < nTeams; i++){ + teamList[i] = teamList[i+1]; + } + } + } + } + + void registerThreadTeam(Tasklet* t, CapEntry* threadTeam){ + monitor.request(t,[=](Tasklet*){ + if(nTeams < MAX_TEAMS){ + teamRefs[nTeams].set(this, threadTeam, threadTeam->cap()); + MLOG_INFO(mlog::pm, "registered thread team on index ", nTeams); + nTeams++; + }else{ + MLOG_INFO(mlog::pm, "ERROR: too many thread teams registered!"); + } + monitor.responseAndRequestDone(); + }); + } + + private: + static constexpr unsigned MAX_TEAMS = MYTHOS_MAX_THREADS; async::NestedMonitorDelegating monitor; CapEntry *sc; CapEntry mySC[MYTHOS_MAX_THREADS]; unsigned nFree; cpu::ThreadID freeList[MYTHOS_MAX_THREADS]; + CapRef teamRefs[MAX_TEAMS]; + unsigned teamList[MAX_TEAMS]; + unsigned nTeams; }; } // namespace mythos diff --git a/kernel/objects/thread-team/objects/ThreadTeam.cc b/kernel/objects/thread-team/objects/ThreadTeam.cc index 7974fea3..8ce7d6e5 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.cc +++ b/kernel/objects/thread-team/objects/ThreadTeam.cc @@ -404,8 +404,10 @@ namespace mythos { if(!tryRunDemandAt(t, id)) { removeUsed(id); - pushFree(id); + //pushFree(id); + ASSERT(pa); state = IDLE; + pa->free(t, id); monitor.responseAndRequestDone(); } }); @@ -480,6 +482,7 @@ namespace mythos { mem->free(*obj); // mem->release(obj) goes throug IKernelObject deletion mechanism RETHROW(res); } + pa->registerThreadTeam(&obj->paTasklet, dstEntry); return *obj; } diff --git a/kernel/objects/thread-team/objects/ThreadTeam.hh b/kernel/objects/thread-team/objects/ThreadTeam.hh index b44004f1..c2a83efd 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.hh +++ b/kernel/objects/thread-team/objects/ThreadTeam.hh @@ -114,6 +114,7 @@ namespace mythos { friend class ThreadTeamFactory; CapRef paRef; ProcessorAllocator* pa; + Tasklet paTasklet; cpu::ThreadID freeList[MYTHOS_MAX_THREADS]; unsigned nFree; cpu::ThreadID usedList[MYTHOS_MAX_THREADS]; From 19a05239c17476b674409ba9d909798060d8b6ef Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Tue, 2 Mar 2021 21:50:44 +0100 Subject: [PATCH 35/42] cleanup init.cc --- kernel/app/init-example/app/init.cc | 81 ++++------------------------- 1 file changed, 9 insertions(+), 72 deletions(-) diff --git a/kernel/app/init-example/app/init.cc b/kernel/app/init-example/app/init.cc index c491f238..d64de335 100644 --- a/kernel/app/init-example/app/init.cc +++ b/kernel/app/init-example/app/init.cc @@ -559,89 +559,26 @@ void test_process(){ MLOG_INFO(mlog::app, "Test process finished"); } -void testCapMapDeletion(){ - MLOG_INFO(mlog::app, "Test CapMap deletion"); - - mythos::PortalLock pl(portal); - mythos::CapMap cs(capAlloc()); - - auto res = cs.create(pl, kmem, CapPtrDepth(12), CapPtrDepth(20), CapPtr(0)).wait(); - ASSERT(res); - - capAlloc.free(cs.cap(), pl); - MLOG_INFO(mlog::app, "Test CapMap deletion finished"); -} - -void pageMapPageFault(){ - MLOG_INFO(mlog::app, "Trigger PageMap page fault"); - - mythos::PortalLock pl(portal); - - mythos::PageMap pm4(capAlloc()); - - auto res = pm4.create(pl, kmem, 4).wait(); - ASSERT(res); - - MLOG_INFO(mlog::app, "Try to delete pm4 -> page fault"); - - capAlloc.free(pm4.cap(), pl); - - MLOG_INFO(mlog::app, "If you can read this, you might have fixed the page fault?!"); -} - -void pageMapDeadlock(){ - MLOG_INFO(mlog::app, "Trigger PageMap deadlock"); - - mythos::PortalLock pl(portal); - - mythos::PageMap pm4(capAlloc()); - mythos::PageMap pm3(capAlloc()); - mythos::PageMap pm2(capAlloc()); - - auto res = pm4.create(pl, kmem, 4).wait(); - ASSERT(res); - res = pm3.create(pl, kmem, 3).wait(); - ASSERT(res); - res = pm2.create(pl, kmem, 2).wait(); - ASSERT(res); - - uintptr_t vaddr = 0x4000000; - - pm4.installMap(pl, pm3, ((vaddr >> 39) & 0x1FF) << 39, 4, - mythos::protocol::PageMap::MapFlags().writable(true).configurable(true)).wait(); - pm3.installMap(pl, pm2, ((vaddr >> 30) & 0x1FF) << 30, 3, - mythos::protocol::PageMap::MapFlags().writable(true).configurable(true)).wait(); - - MLOG_INFO(mlog::app, "Try to delete pm3 -> deadlock"); - - capAlloc.free(pm3.cap(), pl); - - MLOG_INFO(mlog::app, "If you can read this, you might have fixed the deadlock?!"); -} - int main() { char const str[] = "Hello world!"; mythos::syscall_debug(str, sizeof(str)-1); MLOG_ERROR(mlog::app, "application is starting :)", DVARhex(info_ptr), DVARhex(initstack_top)); - //test_float(); - //test_Example(); - //test_Portal(); + test_float(); + test_Example(); + test_Portal(); test_heap(); // heap must be initialized for tls test - //test_tls(); - //test_exceptions(); + test_tls(); + test_exceptions(); //test_InterruptControl(); //test_HostChannel(portal, 24*1024*1024, 2*1024*1024); - //test_ExecutionContext(); - //test_pthreads(); - //test_Rapl(); - //test_TBB(); + test_ExecutionContext(); + test_pthreads(); + test_Rapl(); + test_TBB(); test_process(); - //testCapMapDeletion(); //test_CgaScreen(); - //pageMapPageFault(); - //pageMapDeadlock(); char const end[] = "bye, cruel world!"; mythos::syscall_debug(end, sizeof(end)-1); From 52ffd9657c027a4ef10f00fd3a06273f3f77036d Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Wed, 3 Mar 2021 10:42:58 +0100 Subject: [PATCH 36/42] removed debug output from capentry --- .../capability-spinning/objects/CapEntry.hh | 22 ++----------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/kernel/objects/capability-spinning/objects/CapEntry.hh b/kernel/objects/capability-spinning/objects/CapEntry.hh index ab6a3d04..cd01dcc6 100644 --- a/kernel/objects/capability-spinning/objects/CapEntry.hh +++ b/kernel/objects/capability-spinning/objects/CapEntry.hh @@ -103,16 +103,7 @@ namespace mythos { return ret; } - void lock_next() - { - int loop = 0; - while (!try_lock_next()) { - hwthread_pause(); -#warning remove counting for production - loop++; - PANIC_MSG(loop < 3, "locking next failed too many times"); - } - } + void lock_next() { while (!try_lock_next()) { hwthread_pause(); } } void unlock_next() { @@ -128,16 +119,7 @@ namespace mythos { return ret; } - void lock_cap() - { - int loop = 0; - while (!try_lock_cap()) { - hwthread_pause(); -#warning remove counting for production - loop++; - PANIC_MSG(loop < 3," locking failed too many times"); - } - } + void lock_cap() { while (!try_lock_cap()) { hwthread_pause(); } } void unlock_cap() { From eed7ecf1952c53a8c58e56598a40bc0bcccccb0e Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Wed, 3 Mar 2021 11:00:15 +0100 Subject: [PATCH 37/42] fixed EC exit --- .../execution-context/objects/ExecutionContext.cc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/kernel/objects/execution-context/objects/ExecutionContext.cc b/kernel/objects/execution-context/objects/ExecutionContext.cc index ca8e7f6f..b6767947 100644 --- a/kernel/objects/execution-context/objects/ExecutionContext.cc +++ b/kernel/objects/execution-context/objects/ExecutionContext.cc @@ -425,9 +425,15 @@ namespace mythos { switch(SyscallCode(code)) { case SYSCALL_EXIT: - MLOG_INFO(mlog::syscall, "exit"); - setFlags(IS_TRAPPED); - unsetSchedulingContext(); + { + MLOG_INFO(mlog::syscall, "exit"); + setFlags(IS_TRAPPED); + auto place = currentPlace.load(); + if (place) synchronousAt(place) << [this]() { + this->saveState(); + this->_sched.reset(); + }; + } break; case SYSCALL_POLL: From c00a303c131fcf13217b3cbf7e8ffada928c2dde Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Wed, 3 Mar 2021 11:27:21 +0100 Subject: [PATCH 38/42] revoke demand --- 3rdparty/musl | 2 +- kernel/runtime/cxx/runtime/cxxsupport.cc | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/3rdparty/musl b/3rdparty/musl index 790bd394..b18f6e4b 160000 --- a/3rdparty/musl +++ b/3rdparty/musl @@ -1 +1 @@ -Subproject commit 790bd3943e419933cf56366197b9f6668ae8c53e +Subproject commit b18f6e4b536b9955ff15657513e0fd312a7ca7b3 diff --git a/kernel/runtime/cxx/runtime/cxxsupport.cc b/kernel/runtime/cxx/runtime/cxxsupport.cc index 6fb9e611..bc188710 100644 --- a/kernel/runtime/cxx/runtime/cxxsupport.cc +++ b/kernel/runtime/cxx/runtime/cxxsupport.cc @@ -362,7 +362,7 @@ extern "C" void * mmap(void *start, size_t len, int prot, int flags, int fd, off extern "C" int munmap(void *start, size_t len) { // dummy implementation - //MLOG_DETAIL(mlog::app, "munmap", DVAR(start), DVAR(len)); + MLOG_DETAIL(mlog::app, "munmap", DVAR(start), DVAR(len)); mythos::heap.free(reinterpret_cast(start)); return 0; } @@ -370,7 +370,7 @@ extern "C" int munmap(void *start, size_t len) extern "C" int unmapself(void *start, size_t len) { // see pthread_exit: another pthread might reuse the memory before unmapped thread exited - MLOG_WARN(mlog::app, "unmapself"); + MLOG_DETAIL(mlog::app, "unmapself", DVARhex(start), DVAR(len)); //todo: race condition? mythos::heap.free(reinterpret_cast(start)); threadPool.push(mythos_get_pthread_ec_self(), localPortalPtr); @@ -482,18 +482,19 @@ extern "C" void mythos_pthread_cleanup(pthread_t t){ // memory of target pthread will be free when returning from this function } -extern "C" int mythos_revoke_demand(pthread_t t){ - MLOG_WARN(mlog::app, "revoke demand"); +extern "C" int mythos_revoke_demand_hook(pthread_t t){ + MLOG_DETAIL(mlog::app, "revoke demand", mythos_get_pthread_ec(t)); mythos::PortalLock pl(localPortal); auto ecPtr = mythos_get_pthread_ec(t); mythos::ExecutionContext ec(ecPtr); auto res = team.revokeDemand(pl, ec).wait(); - if(res){ + if(res && res->revoked){ auto portalPtr = getRemotePortalPtr(t); threadPool.push(ecPtr, portalPtr); - MLOG_WARN(mlog::app, "who's gonna free pthreads memory?"); + return 0; } - return res && res->revoked ? 0 : (-1); + MLOG_DETAIL(mlog::app, "revoke failed"); + return (-1); } struct dl_phdr_info @@ -516,7 +517,7 @@ extern char __executable_start; //< provided by the default linker script extern "C" int dl_iterate_phdr( int (*callback) (dl_phdr_info *info, size_t size, void *data), void *data) { - MLOG_ERROR(mlog::app, "dl_iterate_phdr", DVAR((void*)callback), DVAR(&__executable_start)); + MLOG_DETAIL(mlog::app, "dl_iterate_phdr", DVAR((void*)callback), DVAR(&__executable_start)); mythos::elf64::Elf64Image img(&__executable_start); ASSERT(img.isValid()); From 03a31241fa9b33c80b8274b763d20cafa5a65ed6 Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Wed, 3 Mar 2021 11:43:01 +0100 Subject: [PATCH 39/42] moved processor allocator --- .../objects/processor-allocator/mcconf.module | 5 - .../mythos/protocol/ProcessorAllocator.hh | 91 ------------------- .../objects/PluginProcessorAllocator.cc | 31 ------- .../objects/PluginProcessorAllocator.hh | 89 ------------------ kernel/objects/thread-team/mcconf.module | 4 +- .../objects/ProcessorAllocator.cc | 0 .../objects/ProcessorAllocator.hh | 2 - 7 files changed, 2 insertions(+), 220 deletions(-) delete mode 100644 kernel/objects/processor-allocator/mcconf.module delete mode 100644 kernel/objects/processor-allocator/mythos/protocol/ProcessorAllocator.hh delete mode 100644 kernel/objects/processor-allocator/objects/PluginProcessorAllocator.cc delete mode 100644 kernel/objects/processor-allocator/objects/PluginProcessorAllocator.hh rename kernel/objects/{processor-allocator => thread-team}/objects/ProcessorAllocator.cc (100%) rename kernel/objects/{processor-allocator => thread-team}/objects/ProcessorAllocator.hh (97%) diff --git a/kernel/objects/processor-allocator/mcconf.module b/kernel/objects/processor-allocator/mcconf.module deleted file mode 100644 index 4f7b7c08..00000000 --- a/kernel/objects/processor-allocator/mcconf.module +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode:toml; -*- -[module.plugin-processor-allocator] - incfiles = [ "objects/ProcessorAllocator.hh", "mythos/protocol/ProcessorAllocator.hh" ] - kernelfiles = [ "objects/ProcessorAllocator.cc"] - diff --git a/kernel/objects/processor-allocator/mythos/protocol/ProcessorAllocator.hh b/kernel/objects/processor-allocator/mythos/protocol/ProcessorAllocator.hh deleted file mode 100644 index ab7a2571..00000000 --- a/kernel/objects/processor-allocator/mythos/protocol/ProcessorAllocator.hh +++ /dev/null @@ -1,91 +0,0 @@ -/* -*- mode:C++; indent-tabs-mode:nil; -*- */ -/* MIT License -- MyThOS: The Many-Threads Operating System - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Copyright 2020 Philipp Gypser and contributors, BTU Cottbus-Senftenberg - */ -#pragma once - -#include "mythos/protocol/common.hh" - -namespace mythos { - namespace protocol { - - struct ProcessorAllocator { - constexpr static uint8_t proto = PROCESSORALLOCATOR; - - enum Methods : uint8_t { - ALLOC, - RETALLOC, - FREE, - RETFREE - }; - - struct Alloc : public InvocationBase { - constexpr static uint16_t label = (proto<<8) + ALLOC; - Alloc(CapPtr dstMap = null_cap) : InvocationBase(label,getLength(this)) { - addExtraCap(dstMap); - } - - // target cap map - CapPtr dstSpace() const { return this->capPtrs[0]; } - }; - - struct RetAlloc : public InvocationBase { - constexpr static uint16_t label = (proto<<8) + RETALLOC; - RetAlloc(CapPtr sc) : InvocationBase(label,getLength(this)) { - addExtraCap(sc); - } - - // allocated scheduling context - CapPtr sc() const { return this->capPtrs[0]; } - }; - - struct Free : public InvocationBase { - constexpr static uint16_t label = (proto<<8) + FREE; - Free(CapPtr sc) : InvocationBase(label,getLength(this)) { - addExtraCap(sc); - } - - // scheduling context to be freed - CapPtr sc() const { return this->capPtrs[0]; } - }; - - struct RetFree : public InvocationBase { - constexpr static uint16_t label = (proto<<8) + RETFREE; - RetFree() : InvocationBase(label,getLength(this)) { - } - }; - - template - static Error dispatchRequest(IMPL* obj, uint8_t m, ARGS const&...args) { - switch(Methods(m)) { - case ALLOC: return obj->invokeAlloc(args...); - case FREE: return obj->invokeFree(args...); - default: return Error::NOT_IMPLEMENTED; - } - } - - }; - - }// namespace protocol -}// namespace mythos diff --git a/kernel/objects/processor-allocator/objects/PluginProcessorAllocator.cc b/kernel/objects/processor-allocator/objects/PluginProcessorAllocator.cc deleted file mode 100644 index 02323d58..00000000 --- a/kernel/objects/processor-allocator/objects/PluginProcessorAllocator.cc +++ /dev/null @@ -1,31 +0,0 @@ -/* -*- mode:C++; indent-tabs-mode:nil; -*- */ -/* MIT License -- MyThOS: The Many-Threads Operating System - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Copyright 2020 Philipp Gypser and contributors, BTU Cottbus-Senftenberg - */ - -#include "objects/PluginProcessorAllocator.hh" - -mythos::PluginProcessorAllocator pluginProcessorAllocator; -mythos::PluginProcessorAllocatorActivator pluginProcessorAllocatorActivator; - diff --git a/kernel/objects/processor-allocator/objects/PluginProcessorAllocator.hh b/kernel/objects/processor-allocator/objects/PluginProcessorAllocator.hh deleted file mode 100644 index edf39256..00000000 --- a/kernel/objects/processor-allocator/objects/PluginProcessorAllocator.hh +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- mode:C++; indent-tabs-mode:nil; -*- */ -/* MIT License -- MyThOS: The Many-Threads Operating System - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Copyright 2020 Philipp Gypser and contributors, BTU Cottbus-Senftenberg - */ -#pragma once - -#include "objects/ProcessorAllocator.hh" -#include "objects/SchedulingContext.hh" -#include "util/events.hh" -#include "boot/load_init.hh" -#include "mythos/init.hh" -#include "boot/mlog.hh" -#include "util/assert.hh" - -namespace mythos { - class PluginProcessorAllocatorActivator - : public EventHook - { - public: - PluginProcessorAllocatorActivator() { - event::initLoaderEarly.add(this); - } - virtual ~PluginProcessorAllocatorActivator() {} - - void processEvent(boot::InitLoader& loader) override { - MLOG_DETAIL(mlog::pm, "prevent mapping of all scheduling contexts into CSpace"); - loader.processorAllocatorPresent = true; - } - - }; - - class PluginProcessorAllocator - : public EventHook - , public EventHook - { - public: - PluginProcessorAllocator() { - event::initLoader.add(this); - event::idleSC.add(this); - } - virtual ~PluginProcessorAllocator() {} - - void processEvent(boot::InitLoader& loader) override { - MLOG_DETAIL(mlog::pm, "Init processor allocator"); - pa.init(); - MLOG_DETAIL(mlog::pm, "CSset processor allocator"); - OOPS(loader.csSet(init::PROCESSOR_ALLOCATOR, pa)); - auto sc = pa.alloc(); - ASSERT(sc); - MLOG_DETAIL(mlog::pm, "allocated SC for init app", DVAR(init::SCHEDULERS_START+*sc)); - loader.initSC = init::SCHEDULERS_START+*sc; - MLOG_DETAIL(mlog::pm, "map SC for init app"); - loader.csSet(init::SCHEDULERS_START+*sc, boot::getScheduler(*sc)); - - } - - void processEvent(Tasklet* t, cpu::ThreadID id) override { - MLOG_DETAIL(mlog::pm, "idleSc -> freeSC", DVAR(id)); - pa.freeSC(t, id); - } - - LiFoProcessorAllocator pa; - }; - -} // namespace mythos - -extern mythos::PluginProcessorAllocator pluginProcessorAllocator; -extern mythos::PluginProcessorAllocatorActivator pluginProcessorAllocatorActivator; diff --git a/kernel/objects/thread-team/mcconf.module b/kernel/objects/thread-team/mcconf.module index 7ce1e27c..8e5a7c7a 100644 --- a/kernel/objects/thread-team/mcconf.module +++ b/kernel/objects/thread-team/mcconf.module @@ -1,5 +1,5 @@ # -*- mode:toml; -*- [module.objects-thread-team] - incfiles = [ "objects/ThreadTeam.hh", "mythos/protocol/ThreadTeam.hh", "objects/PluginThreadTeam.hh" ] - kernelfiles = [ "objects/ThreadTeam.cc", "objects/PluginThreadTeam.cc"] + incfiles = [ "objects/ProcessorAllocator.hh", "objects/ThreadTeam.hh", "mythos/protocol/ThreadTeam.hh", "objects/PluginThreadTeam.hh" ] + kernelfiles = [ "objects/ProcessorAllocator.cc", "objects/ThreadTeam.cc", "objects/PluginThreadTeam.cc"] diff --git a/kernel/objects/processor-allocator/objects/ProcessorAllocator.cc b/kernel/objects/thread-team/objects/ProcessorAllocator.cc similarity index 100% rename from kernel/objects/processor-allocator/objects/ProcessorAllocator.cc rename to kernel/objects/thread-team/objects/ProcessorAllocator.cc diff --git a/kernel/objects/processor-allocator/objects/ProcessorAllocator.hh b/kernel/objects/thread-team/objects/ProcessorAllocator.hh similarity index 97% rename from kernel/objects/processor-allocator/objects/ProcessorAllocator.hh rename to kernel/objects/thread-team/objects/ProcessorAllocator.hh index 1d6a4e6a..bbead690 100644 --- a/kernel/objects/processor-allocator/objects/ProcessorAllocator.hh +++ b/kernel/objects/thread-team/objects/ProcessorAllocator.hh @@ -29,9 +29,7 @@ #include "objects/IFactory.hh" #include "objects/IKernelObject.hh" #include "cpu/hwthreadid.hh" -#include "mythos/protocol/ProcessorAllocator.hh" #include "boot/mlog.hh" -#include "objects/RevokeOperation.hh" #include "async/IResult.hh" namespace mythos { From 1641db0d10206cfd85ee9c8ea2132c7970d1742c Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Thu, 4 Mar 2021 10:23:56 +0100 Subject: [PATCH 40/42] thread team core limitation invocation --- kernel/app/init-example/app/init.cc | 5 +++ .../thread-team/mythos/protocol/ThreadTeam.hh | 16 +++++++- .../objects/thread-team/objects/ThreadTeam.cc | 38 ++++++++++++++++--- .../objects/thread-team/objects/ThreadTeam.hh | 5 +++ kernel/runtime/kobject/runtime/ThreadTeam.hh | 4 ++ 5 files changed, 61 insertions(+), 7 deletions(-) diff --git a/kernel/app/init-example/app/init.cc b/kernel/app/init-example/app/init.cc index d64de335..cc09e33c 100644 --- a/kernel/app/init-example/app/init.cc +++ b/kernel/app/init-example/app/init.cc @@ -427,6 +427,11 @@ long ParallelFib( long n ) { void test_TBB(){ MLOG_INFO(mlog::app, "Test TBB"); + //test thread team limitation + mythos::PortalLock pl(portal); + auto res = team.setLimit(pl, 2).wait(); + TEST(res); + tbb::enableDynamicThreading(); long f = 40; diff --git a/kernel/objects/thread-team/mythos/protocol/ThreadTeam.hh b/kernel/objects/thread-team/mythos/protocol/ThreadTeam.hh index 2b70e39e..3d6396c6 100644 --- a/kernel/objects/thread-team/mythos/protocol/ThreadTeam.hh +++ b/kernel/objects/thread-team/mythos/protocol/ThreadTeam.hh @@ -42,7 +42,8 @@ namespace mythos { REVOKEDEMAND, RETREVOKEDEMAND, RUNNEXTTOEC, - RETRUNNEXTTOEC + RETRUNNEXTTOEC, + SETLIMIT, }; //needs to be equal to pthread_alloc_type_t in pthread.h of musl @@ -140,12 +141,25 @@ namespace mythos { } }; + // restrict to maximum number of threads + struct SetLimit : public InvocationBase { + constexpr static uint16_t label = (proto<<8) + SETLIMIT; + SetLimit(unsigned limit) + : InvocationBase(label,getLength(this)) + , limit(limit) + {} + + // maximum number of threads to be allocated + unsigned limit; + }; + template static Error dispatchRequest(IMPL* obj, uint8_t m, ARGS const&...args) { switch(Methods(m)) { case TRYRUNEC: return obj->invokeTryRunEC(args...); case REVOKEDEMAND: return obj->invokeRevokeDemand(args...); case RUNNEXTTOEC: return obj->invokeRunNextToEC(args...); + case SETLIMIT: return obj->invokeSetLimit(args...); default: return Error::NOT_IMPLEMENTED; } } diff --git a/kernel/objects/thread-team/objects/ThreadTeam.cc b/kernel/objects/thread-team/objects/ThreadTeam.cc index 8ce7d6e5..ca72640f 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.cc +++ b/kernel/objects/thread-team/objects/ThreadTeam.cc @@ -46,6 +46,7 @@ namespace mythos { sc->resetThreadTeam(); //todo: synchronize!!!! pa->free(*used); + numAllocated--; used = popUsed(); } @@ -57,6 +58,7 @@ namespace mythos { sc->resetThreadTeam(); //todo:: synchronize!!! pa->free(*free); + numAllocated--; free = popFree(); } del.deleteObject(del_handle); @@ -111,6 +113,7 @@ namespace mythos { if(id){ MLOG_DETAIL(mlog::pm, DVAR(*id)); + numAllocated++; auto sce = pa->getSC(*id); TypedCap sc(sce->cap()); sc->registerThreadTeam(this); @@ -126,7 +129,7 @@ namespace mythos { if(data.allocType == protocol::ThreadTeam::DEMAND){ if(enqueueDemand(*ece)){ - MLOG_DETAIL(mlog::pm, "enqueued to demand list"); + MLOG_DETAIL(mlog::pm, "enqueued to demand list", DVARhex(*ece)); ret->setResponse(protocol::ThreadTeam::RetTryRunEC::ALLOCATED); } }else if(data.allocType == protocol::ThreadTeam::FORCE){ @@ -152,6 +155,7 @@ namespace mythos { ASSERT(tmp_id != INV_ID); if(state == INVOCATION){ + MLOG_DETAIL(mlog::pm, "state = INVOCATION"); ASSERT(tmp_msg); ASSERT(tmp_msg->getMethod() == protocol::ThreadTeam::TRYRUNEC); @@ -169,6 +173,7 @@ namespace mythos { tmp_msg->replyResponse(Error::GENERIC_ERROR); } }else if(state == SC_NOTIFY){ + MLOG_DETAIL(mlog::pm, "state = SC_NOTIFY"); if(bound){ // remove ec from demand queue removeDemand(tmp_ec, true); @@ -191,11 +196,14 @@ namespace mythos { , tmp_msg(nullptr) , tmp_id(INV_ID) , tmp_ec(nullptr) + , rm_ec(nullptr) , state(IDLE) , pa(nullptr) , nFree(0) , nUsed(0) , nDemand(0) + , limit(0) + , numAllocated(0) { for(unsigned d = 0; d < MYTHOS_MAX_THREADS; d++){ demandList[d] = d; @@ -208,8 +216,9 @@ namespace mythos { ASSERT(ec); auto id = popFree(); - if(!id){ + if(!id && !limitReached()){ id = pa->alloc(); + if(id){ numAllocated++; } } if(id){ @@ -271,6 +280,9 @@ namespace mythos { TypedCap ec(ece); ASSERT(ec); tryRunAt(t, *ec, *id); + }else if(limitReached()){ + MLOG_DETAIL(mlog::pm, "limit reached!"); + response(t, optional()); }else{ MLOG_DETAIL(mlog::pm, "try alloc SC from PA"); ASSERT(pa); @@ -304,6 +316,18 @@ namespace mythos { return Error::SUCCESS; } + Error ThreadTeam::invokeSetLimit(Tasklet* /*t*/, Cap, IInvocation* msg){ + MLOG_DETAIL(mlog::pm, __func__); + ASSERT(state == INVOCATION); + + auto data = msg->getMessage()->read(); + auto oldLimit = limit; + limit = data.limit; + MLOG_DETAIL(mlog::pm, DVAR(oldLimit), DVAR(limit)); + + return Error::SUCCESS; + } + Error ThreadTeam::invokeRunNextToEC(Tasklet* /*t*/, Cap, IInvocation* /*msg*/){ MLOG_ERROR(mlog::pm, __func__, " NYI!"); return Error::NOT_IMPLEMENTED; @@ -356,7 +380,7 @@ namespace mythos { } bool ThreadTeam::enqueueDemand(CapEntry* ec){ - MLOG_DETAIL(mlog::pm, __func__); + MLOG_DETAIL(mlog::pm, __func__, DVARhex(ec)); ASSERT(state == INVOCATION); if(nDemand < MYTHOS_MAX_THREADS){ demandEC[demandList[nDemand]].set(this, ec, ec->cap()); @@ -383,7 +407,7 @@ namespace mythos { demandList[nDemand] = di; //reset entry if(resetRef){ - tmp_ec = *d; + rm_ec = *d; demandEC[di].reset(); } //dumpDemand(); @@ -408,6 +432,7 @@ namespace mythos { ASSERT(pa); state = IDLE; pa->free(t, id); + numAllocated--; monitor.responseAndRequestDone(); } }); @@ -423,6 +448,7 @@ namespace mythos { TypedCap ec(demandEC[di]); ASSERT(ec); MLOG_DETAIL(mlog::pm, DVARhex(*ec), DVAR(id)); + tmp_ec = *ec; //try to run ec tryRunAt(t, *ec, id); return true; @@ -436,9 +462,9 @@ namespace mythos { void ThreadTeam::unbind(optional ec){ MLOG_DETAIL(mlog::pm, __func__, DVARhex(ec)); if(ec){ - if(*ec == tmp_ec){ + if(*ec == rm_ec){ MLOG_DETAIL(mlog::pm, "synchronous unbind"); - tmp_ec = nullptr; + rm_ec = nullptr; }else{ MLOG_DETAIL(mlog::pm, "asynchronous unbind"); //todo: tasklet valid after unbind? diff --git a/kernel/objects/thread-team/objects/ThreadTeam.hh b/kernel/objects/thread-team/objects/ThreadTeam.hh index c2a83efd..4846b314 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.hh +++ b/kernel/objects/thread-team/objects/ThreadTeam.hh @@ -70,6 +70,7 @@ namespace mythos { Error invokeTryRunEC(Tasklet* t, Cap, IInvocation* msg); Error invokeRevokeDemand(Tasklet* t, Cap, IInvocation* msg); Error invokeRunNextToEC(Tasklet* t, Cap, IInvocation* msg); + Error invokeSetLimit(Tasklet* t, Cap, IInvocation* msg); void bind(optional paPtr); void unbind(optional ); @@ -93,6 +94,7 @@ namespace mythos { bool removeDemand(ExecutionContext* ec, bool resetRef); bool tryRunDemandAt(Tasklet* t, cpu::ThreadID id); void dumpDemand(); + bool limitReached() { return limit && numAllocated >= limit; } private: LinkedList::Queueable del_handle = {this}; @@ -104,6 +106,7 @@ namespace mythos { static constexpr cpu::ThreadID INV_ID = cpu::ThreadID(-1); cpu::ThreadID tmp_id; ExecutionContext* tmp_ec; + ExecutionContext* rm_ec; enum OperationalState{ IDLE, INVOCATION, @@ -124,6 +127,8 @@ namespace mythos { // index >= nDemand = demandEC slot is free unsigned demandList[MYTHOS_MAX_THREADS]; // indexes to demandEC unsigned nDemand; + unsigned limit; + unsigned numAllocated; }; class ThreadTeamFactory : public FactoryBase diff --git a/kernel/runtime/kobject/runtime/ThreadTeam.hh b/kernel/runtime/kobject/runtime/ThreadTeam.hh index 067a58de..2df51f38 100644 --- a/kernel/runtime/kobject/runtime/ThreadTeam.hh +++ b/kernel/runtime/kobject/runtime/ThreadTeam.hh @@ -78,6 +78,10 @@ namespace mythos { PortalFuture revokeDemand(PortalLock pr, ExecutionContext ec){ return pr.invoke(_cap, ec.cap()); } + + PortalFuture setLimit(PortalLock pr, unsigned limit){ + return pr.invoke(_cap, limit); + } }; } // namespace mythos From 2d3d6fbe72283f15ebf9b27ed3a151192db568ff Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Fri, 5 Mar 2021 09:57:41 +0100 Subject: [PATCH 41/42] fixed musl revoke demand --- 3rdparty/musl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/musl b/3rdparty/musl index b18f6e4b..88986a3b 160000 --- a/3rdparty/musl +++ b/3rdparty/musl @@ -1 +1 @@ -Subproject commit b18f6e4b536b9955ff15657513e0fd312a7ca7b3 +Subproject commit 88986a3bd33c6b5b97c8ec4502cc97093155cfe9 From 245619e1b449fa51b5b7973e35d61ceda20e0980 Mon Sep 17 00:00:00 2001 From: Philipp Gypser Date: Fri, 5 Mar 2021 11:24:03 +0100 Subject: [PATCH 42/42] combined test TBB RAPL ThreadTeam --- kernel/app/init-example/app/init.cc | 53 ++++++++++++++++++- .../thread-team/objects/ProcessorAllocator.cc | 2 +- .../objects/thread-team/objects/ThreadTeam.cc | 13 ++--- .../objects/thread-team/objects/ThreadTeam.hh | 2 +- kernel/runtime/cxx/runtime/cxxsupport.cc | 8 +-- kernel/runtime/tbb/mcconf.module | 1 + 6 files changed, 65 insertions(+), 14 deletions(-) diff --git a/kernel/app/init-example/app/init.cc b/kernel/app/init-example/app/init.cc index cc09e33c..3b803976 100644 --- a/kernel/app/init-example/app/init.cc +++ b/kernel/app/init-example/app/init.cc @@ -419,8 +419,10 @@ class FibTask: public tbb::task { long ParallelFib( long n ) { long sum; + tbb::task_scheduler_init tsi; // manually initialize TBB scheduler FibTask& a = *new(tbb::task::allocate_root()) FibTask(n,&sum); tbb::task::spawn_root_and_wait(a); + tsi.blocking_terminate(); // wait until TBB is terminated return sum; } @@ -564,6 +566,52 @@ void test_process(){ MLOG_INFO(mlog::app, "Test process finished"); } +void test_scalability(){ + MLOG_INFO(mlog::app, "Test runtime/energy scalability"); + mythos::PortalLock pl(portal); + timeval start_run, end_run; + + tbb::enableDynamicThreading(); + long f = 40; + + for(unsigned nThreads = 2; nThreads <= info_ptr->getNumThreads(); nThreads++){ + auto res = team.setLimit(pl, nThreads).wait(); + ASSERT(res); + + asm volatile ("":::"memory"); + auto start = rapl.getRaplVal(pl).wait().get(); + gettimeofday(&start_run, 0); + asm volatile ("":::"memory"); + + auto result = ParallelFib(f); + + asm volatile ("":::"memory"); + auto end = rapl.getRaplVal(pl).wait().get(); + gettimeofday(&end_run, 0); + asm volatile ("":::"memory"); + + double seconds =(end_run.tv_usec - start_run.tv_usec)/1000000.0 + end_run.tv_sec - start_run.tv_sec; + double pp0 = (end.pp0 - start.pp0) * pow(0.5, start.cpu_energy_units); + double pp1 = (end.pp1 - start.pp1) * pow(0.5, start.cpu_energy_units); + double psys = (end.psys - start.psys) * pow(0.5, start.cpu_energy_units); + double pkg = (end.pkg - start.pkg) * pow(0.5, start.cpu_energy_units); + double dram = (end.dram - start.dram) * pow(0.5, start.dram_energy_units); + + std::cout << "Prime test: fib(" << f << ") = " << result << ", "<< seconds << " seonds, " << nThreads + << " threads" << std::endl; + + std::cout << "Energy consumption (energy/avg. power):" + << " PP0:" << pp0 << "J/" << pp0/seconds << "W" + << " PP1:" << pp1 << "J/" << pp1/seconds << "W" + << " Platform:" << psys << "J/" << psys/seconds << "W" + << " Package: " << pkg << "J/ " << pkg/seconds << "W" + << " DRAM:" << dram << "J/" << dram/seconds << "W" + << std::endl; + } + + MLOG_INFO(mlog::app, "Finished scalability test"); +} + int main() { char const str[] = "Hello world!"; @@ -580,8 +628,9 @@ int main() //test_HostChannel(portal, 24*1024*1024, 2*1024*1024); test_ExecutionContext(); test_pthreads(); - test_Rapl(); - test_TBB(); + //test_Rapl(); + //test_TBB(); + test_scalability(); test_process(); //test_CgaScreen(); diff --git a/kernel/objects/thread-team/objects/ProcessorAllocator.cc b/kernel/objects/thread-team/objects/ProcessorAllocator.cc index 39dfc30b..445ec382 100644 --- a/kernel/objects/thread-team/objects/ProcessorAllocator.cc +++ b/kernel/objects/thread-team/objects/ProcessorAllocator.cc @@ -57,7 +57,7 @@ namespace mythos { } optional ProcessorAllocator::alloc(){ - MLOG_DETAIL(mlog::pm, __func__); + MLOG_INFO(mlog::pm, __func__); optional ret; if(nFree > 0){ nFree--; diff --git a/kernel/objects/thread-team/objects/ThreadTeam.cc b/kernel/objects/thread-team/objects/ThreadTeam.cc index ca72640f..927e884b 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.cc +++ b/kernel/objects/thread-team/objects/ThreadTeam.cc @@ -162,7 +162,7 @@ namespace mythos { auto ret = tmp_msg->getMessage()->cast(); if(bound){ - MLOG_DETAIL(mlog::pm, "EC successfully bound to SC"); + MLOG_INFO(mlog::pm, "EC successfully bound to SC"); pushUsed(tmp_id); //allready set! ret->setResponse(protocol::ThreadTeam::RetTryRunEC::ALLOCATED); tmp_msg->replyResponse(Error::SUCCESS); @@ -175,6 +175,7 @@ namespace mythos { }else if(state == SC_NOTIFY){ MLOG_DETAIL(mlog::pm, "state = SC_NOTIFY"); if(bound){ + MLOG_INFO(mlog::pm, "EC successfully bound to SC"); // remove ec from demand queue removeDemand(tmp_ec, true); }else{ @@ -259,7 +260,7 @@ namespace mythos { } Error ThreadTeam::invokeTryRunEC(Tasklet* t, Cap, IInvocation* msg){ - MLOG_DETAIL(mlog::pm, __func__); + MLOG_INFO(mlog::pm, __func__); ASSERT(state == INVOCATION); auto data = msg->getMessage()->read(); @@ -293,7 +294,7 @@ namespace mythos { } Error ThreadTeam::invokeRevokeDemand(Tasklet* /*t*/, Cap, IInvocation* msg){ - MLOG_DETAIL(mlog::pm, __func__); + MLOG_INFO(mlog::pm, __func__); ASSERT(state == INVOCATION); auto data = msg->getMessage()->read(); @@ -317,7 +318,7 @@ namespace mythos { } Error ThreadTeam::invokeSetLimit(Tasklet* /*t*/, Cap, IInvocation* msg){ - MLOG_DETAIL(mlog::pm, __func__); + MLOG_INFO(mlog::pm, __func__); ASSERT(state == INVOCATION); auto data = msg->getMessage()->read(); @@ -420,13 +421,13 @@ namespace mythos { } void ThreadTeam::notifyIdle(Tasklet* t, cpu::ThreadID id) { - MLOG_DETAIL(mlog::pm, __func__, DVAR(id)); + MLOG_INFO(mlog::pm, __func__, DVAR(id)); monitor.request(t, [=](Tasklet*){ ASSERT(state == IDLE); ASSERT(tmp_id == INV_ID); state = SC_NOTIFY; - if(!tryRunDemandAt(t, id)) { + if(numAllocated > limit || !tryRunDemandAt(t, id)) { removeUsed(id); //pushFree(id); ASSERT(pa); diff --git a/kernel/objects/thread-team/objects/ThreadTeam.hh b/kernel/objects/thread-team/objects/ThreadTeam.hh index 4846b314..cc2a5b49 100644 --- a/kernel/objects/thread-team/objects/ThreadTeam.hh +++ b/kernel/objects/thread-team/objects/ThreadTeam.hh @@ -94,7 +94,7 @@ namespace mythos { bool removeDemand(ExecutionContext* ec, bool resetRef); bool tryRunDemandAt(Tasklet* t, cpu::ThreadID id); void dumpDemand(); - bool limitReached() { return limit && numAllocated >= limit; } + bool limitReached() { return limit != 0 && numAllocated >= limit; } private: LinkedList::Queueable del_handle = {this}; diff --git a/kernel/runtime/cxx/runtime/cxxsupport.cc b/kernel/runtime/cxx/runtime/cxxsupport.cc index bc188710..fce6d6c0 100644 --- a/kernel/runtime/cxx/runtime/cxxsupport.cc +++ b/kernel/runtime/cxx/runtime/cxxsupport.cc @@ -187,9 +187,8 @@ extern "C" [[noreturn]] void __assert_fail (const char *expr, const char *file, mythos::Event<> groupExit; void mythosExit(){ - //todo: ASSERT(myEC == init::EC) + PANIC(mythos_get_pthread_ec_self() == init::EC); - //todo: free capspace, all ECs, mythos::PortalLock pl(localPortal); MLOG_DETAIL(mlog::app, "Free all dynamically allocated Caps"); capAlloc.freeAll(pl); @@ -294,8 +293,9 @@ extern "C" long mythos_musl_syscall( MLOG_WARN(mlog::app, "syscall madvise NYI"); return 0; case 39: // getpid - MLOG_WARN(mlog::app, "syscall getpid NYI"); - return mythos_get_pthread_ec_self(); + MLOG_DETAIL(mlog::app, "syscall getpid NYI"); + //todo: use proper process identification + return 4711; case 60: // exit(exit_code) MLOG_DETAIL(mlog::app, "syscall exit", DVAR(a1)); pthreadCleaner.exit(); diff --git a/kernel/runtime/tbb/mcconf.module b/kernel/runtime/tbb/mcconf.module index fdc47b80..b612ed74 100644 --- a/kernel/runtime/tbb/mcconf.module +++ b/kernel/runtime/tbb/mcconf.module @@ -4,4 +4,5 @@ makefile_head = ''' APP_CPPFLAGS += -I ${vars.tbb_inc_path} +INITAPP_CXXFLAGS += -DTBB_USE_EXCEPTIONS -DTBB_PREVIEW_WAITING_FOR_WORKERS '''