Skip to content

Commit

Permalink
add new C-wrappers to expose module API
Browse files Browse the repository at this point in the history
The commit af2d371 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 <[email protected]>
  • Loading branch information
wkozaczuk committed Jan 19, 2022
1 parent 05c06ba commit 182499c
Show file tree
Hide file tree
Showing 3 changed files with 228 additions and 1 deletion.
119 changes: 119 additions & 0 deletions core/osv_c_wrappers.cc
Original file line number Diff line number Diff line change
@@ -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) {
Expand All @@ -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;
}
3 changes: 3 additions & 0 deletions include/osv/export.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
107 changes: 106 additions & 1 deletion include/osv/osv_c_wrappers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 182499c

Please sign in to comment.