The commit af2d371a61f6ab1eb5a066a0c3e93230faf6611c introduced ability to build OSv kernel with most symbols but subset of glibc hidden. The regular Linux glibc apps should run fine on such kernel, but unfortunately many unit tests and various internal OSv apps (so called modules) do not as they have been coded to use many internal API symbols. One such example is httpserver monitoring api module that exposes various monitoring API REST endpoints.
At some point XLAB introduced C-wrappers API made of single C-style osv_get_all_app_threads() functions. This patch enhances the C-wrappers API by adding 9 more functions intended to be used by httpserver monitoring api module. Please note that new C-style API will open up access to relevant functionality to new apps/modules implemented in languages different than C++. Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com> --- core/osv_c_wrappers.cc | 121 +++++++++++++++++++++++++++++++++++ include/osv/export.h | 3 + include/osv/osv_c_wrappers.h | 105 +++++++++++++++++++++++++++++- 3 files changed, 228 insertions(+), 1 deletion(-) diff --git a/core/osv_c_wrappers.cc b/core/osv_c_wrappers.cc index 137f2c6f..dbda0613 100644 --- a/core/osv_c_wrappers.cc +++ b/core/osv_c_wrappers.cc @@ -1,12 +1,27 @@ +/* + * Copyright (C) 2022 Waldemar Kozaczuk + * Copyright (C) 2016 XLAB, d.o.o. + * + * This work is open source software, licensed under the terms of the + * BSD license as described in the LICENSE file in the top-level directory. + */ #include <osv/osv_c_wrappers.h> +#include <osv/export.h> #include <osv/debug.hh> #include <osv/sched.hh> #include <osv/app.hh> +#include <osv/run.hh> +#include <osv/version.hh> +#include <osv/commands.hh> +#include <osv/firmware.hh> +#include <osv/hypervisor.hh> +#include <vector> using namespace osv; using namespace sched; +extern "C" OSV_MODULE_API int osv_get_all_app_threads(pid_t tid, pid_t** tid_arr, size_t *len) { thread* app_thread = tid==0? thread::current(): thread::find_by_id(tid); if (app_thread == nullptr) { @@ -28,3 +43,109 @@ int osv_get_all_app_threads(pid_t tid, pid_t** tid_arr, size_t *len) { } return 0; } + +static void free_threads_names(std::vector<osv_thread> &threads) { + for (auto &t : threads) { + if (t.name) { + free(t.name); + } + } +} + +static char* str_to_c_str(const std::string& str) { + auto len = str.size(); + char *buf = static_cast<char*>(malloc(len + 1)); // This will be free()-ed in C world + if (buf) { + std::copy(str.begin(), str.end(), buf); + buf[len] = '\0'; + return buf; + } else { + return nullptr; + } +} + +extern "C" OSV_MODULE_API +int osv_get_all_threads(osv_thread** thread_arr, size_t *len) { + using namespace std::chrono; + std::vector<osv_thread> threads; + + osv_thread thread; + bool str_copy_error = false; + sched::with_all_threads([&](sched::thread &t) { + thread.id = t.id(); + auto tcpu = t.tcpu(); + thread.cpu_id = tcpu ? tcpu->id : -1; + thread.cpu_ms = duration_cast<milliseconds>(t.thread_clock()).count(); + thread.switches = t.stat_switches.get(); + thread.migrations = t.stat_migrations.get(); + thread.preemptions = t.stat_preemptions.get(); + thread.name = str_to_c_str(t.name()); + if (!thread.name) { + str_copy_error = true; + } + thread.priority = t.priority(); + thread.stack_size = t.get_stack_info().size; + thread.status = static_cast<osv_thread_status>(static_cast<int>(t.get_status())); + threads.push_back(thread); + }); + + if (str_copy_error) { + goto error; + } + + *thread_arr = (osv_thread*)malloc(threads.size()*sizeof(osv_thread)); + if (*thread_arr == nullptr) { + goto error; + } + + std::copy(threads.begin(), threads.end(), *thread_arr); + *len = threads.size(); + return 0; + +error: + free_threads_names(threads); + *len = 0; + return ENOMEM; +} + +extern "C" OSV_MODULE_API +char *osv_version() { + return str_to_c_str(osv::version()); +} + +extern "C" OSV_MODULE_API +char *osv_cmdline() { + return str_to_c_str(osv::getcmdline()); +} + +extern "C" OSV_MODULE_API +char *osv_hypervisor_name() { + return str_to_c_str(osv::hypervisor_name()); +} + +extern "C" OSV_MODULE_API +char *osv_firmware_vendor() { + return str_to_c_str(osv::firmware_vendor()); +} + +extern "C" OSV_MODULE_API +char *osv_processor_features() { + return str_to_c_str(processor::features_str()); +} + +extern char debug_buffer[DEBUG_BUFFER_SIZE]; +extern "C" OSV_MODULE_API +const char *osv_debug_buffer() { + return debug_buffer; +} + +extern "C" OSV_MODULE_API +void osv_current_app_on_termination_request(void (*handler)()) { + osv::this_application::on_termination_request(handler); +} + +extern bool verbose; +extern "C" OSV_MODULE_API +bool osv_debug_enabled() { + return verbose; +} diff --git a/include/osv/export.h b/include/osv/export.h index c03659b8..b21ba561 100644 --- a/include/osv/export.h +++ b/include/osv/export.h @@ -32,6 +32,9 @@ // This is to expose some symbols in libsolaris.so #define OSV_LIB_SOLARIS_API __attribute__((__visibility__("default"))) +// +// This is to expose some OSv functions intended to be used by modules +#define OSV_MODULE_API __attribute__((__visibility__("default"))) // In some very few cases, when source files are compiled without visibility // flag in order to expose most symbols in the corresponding file, there are some specific diff --git a/include/osv/osv_c_wrappers.h b/include/osv/osv_c_wrappers.h index 94f07ad1..bb7d52a8 100644 --- a/include/osv/osv_c_wrappers.h +++ b/include/osv/osv_c_wrappers.h @@ -8,20 +8,123 @@ #ifndef INCLUDED_OSV_C_WRAPPERS_H #define INCLUDED_OSV_C_WRAPPERS_H +#include <limits.h> #include <sys/types.h> +#include <osv/mount.h> #ifdef __cplusplus extern "C" { #endif +enum osv_thread_status { + invalid, + prestarted, + unstarted, + waiting, + sending_lock, + running, + queued, + waking, + terminating, + terminated +}; + +struct osv_thread { + // 32-bit thread id + long id; + + // CPU the thread is running on + long cpu_id; + + // Total CPU time used by the thread (in milliseconds) + long cpu_ms; + + // Number of times this thread was context-switched in + long switches; + + // Number of times this thread was migrated between CPUs + long migrations; + + // Number of times this thread was preempted (still runnable, but switched out) + long preemptions; + + float priority; + long stack_size; + + enum osv_thread_status status; + + // Thread name + char* name; +}; + /* Save in *tid_arr array TIDs of all threads from app which "owns" input tid/thread. -*tid_arr is allocated with malloc, *len holds lenght. +*tid_arr is allocated with malloc, *len holds length. Caller is responsible to free tid_arr. Returns 0 on success, error code on error. */ int osv_get_all_app_threads(pid_t tid, pid_t** tid_arr, size_t* len); +/* +Save in *thread_arr array info about all threads. +*thread_arr is allocated with malloc, *len holds length. +Caller is responsible to free thread_arr and thread names +in osv_thread struct. +Returns 0 on success, error code on error. +*/ +int osv_get_all_threads(osv_thread** thread_arr, size_t *len); + +/* + * Return OSv version as C string. The returned C string is + * allocated with malloc and caller is responsible to free it + * if non null. + */ +char *osv_version(); + +/* + * Return OSv command line C string. The returned C string is + * allocated with malloc and caller is responsible to free it + * if non null. + */ +char *osv_cmdline(); + +/* + * Return hypervisor name as C string. The returned C string is + * allocated with malloc and caller is responsible to free it + * if non null. + */ +char *osv_hypervisor_name(); + +/* + * Return firmware vendor as C string. The returned C string is + * allocated with malloc and caller is responsible to free it + * if non null. + */ +char *osv_firmware_vendor(); + +/* + * Return processor features as C string. The returned C string is + * allocated with malloc and caller is responsible to free it + * if non null. + */ +char *osv_processor_features(); + +/* + * Return pointer to OSv debug buffer. + */ +const char *osv_debug_buffer(); + +/* + * Return true if OSv debug flag (--verbose) is enabled, otherwise return false. + */ +bool osv_debug_enabled(); + +/* + * Pass a function pointer of a routine which will be invoked + * upon termination of the current app. Useful for resources cleanup. + */ +void osv_current_app_on_termination_request(void (*handler)()); + #ifdef __cplusplus } #endif -- 2.31.1 -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to osv-dev+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/osv-dev/20220117055538.139407-1-jwkozaczuk%40gmail.com.