From: Waldemar Kozaczuk <jwkozac...@gmail.com>
Committer: Waldemar Kozaczuk <jwkozac...@gmail.com>
Branch: master

add new C-wrappers to expose module API

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>

---
diff --git a/core/osv_c_wrappers.cc b/core/osv_c_wrappers.cc
--- 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,107 @@ 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;
+}
+
+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
--- 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
--- a/include/osv/osv_c_wrappers.h
+++ b/include/osv/osv_c_wrappers.h
@@ -8,20 +8,125 @@
 #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
 
+// This C enum should be kept in sync with the C++ enum class 
+// sched::thread::status defined in sched.hh
+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

-- 
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/00000000000002e4f505d5f63d5c%40google.com.

Reply via email to