Skip to content

Commit 182499c

Browse files
committed
add new C-wrappers to expose module API
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]>
1 parent 05c06ba commit 182499c

File tree

3 files changed

+228
-1
lines changed

3 files changed

+228
-1
lines changed

core/osv_c_wrappers.cc

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,27 @@
1+
/*
2+
* Copyright (C) 2022 Waldemar Kozaczuk
3+
* Copyright (C) 2016 XLAB, d.o.o.
4+
*
5+
* This work is open source software, licensed under the terms of the
6+
* BSD license as described in the LICENSE file in the top-level directory.
7+
*/
18

29
#include <osv/osv_c_wrappers.h>
10+
#include <osv/export.h>
311
#include <osv/debug.hh>
412
#include <osv/sched.hh>
513
#include <osv/app.hh>
14+
#include <osv/run.hh>
15+
#include <osv/version.hh>
16+
#include <osv/commands.hh>
17+
#include <osv/firmware.hh>
18+
#include <osv/hypervisor.hh>
19+
#include <vector>
620

721
using namespace osv;
822
using namespace sched;
923

24+
extern "C" OSV_MODULE_API
1025
int osv_get_all_app_threads(pid_t tid, pid_t** tid_arr, size_t *len) {
1126
thread* app_thread = tid==0? thread::current(): thread::find_by_id(tid);
1227
if (app_thread == nullptr) {
@@ -28,3 +43,107 @@ int osv_get_all_app_threads(pid_t tid, pid_t** tid_arr, size_t *len) {
2843
}
2944
return 0;
3045
}
46+
47+
static void free_threads_names(std::vector<osv_thread> &threads) {
48+
for (auto &t : threads) {
49+
if (t.name) {
50+
free(t.name);
51+
}
52+
}
53+
}
54+
55+
static char* str_to_c_str(const std::string& str) {
56+
auto len = str.size();
57+
char *buf = static_cast<char*>(malloc(len + 1)); // This will be free()-ed in C world
58+
if (buf) {
59+
std::copy(str.begin(), str.end(), buf);
60+
buf[len] = '\0';
61+
}
62+
return buf;
63+
}
64+
65+
extern "C" OSV_MODULE_API
66+
int osv_get_all_threads(osv_thread** thread_arr, size_t *len) {
67+
using namespace std::chrono;
68+
std::vector<osv_thread> threads;
69+
70+
osv_thread thread;
71+
bool str_copy_error = false;
72+
sched::with_all_threads([&](sched::thread &t) {
73+
thread.id = t.id();
74+
auto tcpu = t.tcpu();
75+
thread.cpu_id = tcpu ? tcpu->id : -1;
76+
thread.cpu_ms = duration_cast<milliseconds>(t.thread_clock()).count();
77+
thread.switches = t.stat_switches.get();
78+
thread.migrations = t.stat_migrations.get();
79+
thread.preemptions = t.stat_preemptions.get();
80+
thread.name = str_to_c_str(t.name());
81+
if (!thread.name) {
82+
str_copy_error = true;
83+
}
84+
thread.priority = t.priority();
85+
thread.stack_size = t.get_stack_info().size;
86+
thread.status = static_cast<osv_thread_status>(static_cast<int>(t.get_status()));
87+
threads.push_back(thread);
88+
});
89+
90+
if (str_copy_error) {
91+
goto error;
92+
}
93+
94+
*thread_arr = (osv_thread*)malloc(threads.size()*sizeof(osv_thread));
95+
if (*thread_arr == nullptr) {
96+
goto error;
97+
}
98+
99+
std::copy(threads.begin(), threads.end(), *thread_arr);
100+
*len = threads.size();
101+
return 0;
102+
103+
error:
104+
free_threads_names(threads);
105+
*len = 0;
106+
return ENOMEM;
107+
}
108+
109+
extern "C" OSV_MODULE_API
110+
char *osv_version() {
111+
return str_to_c_str(osv::version());
112+
}
113+
114+
extern "C" OSV_MODULE_API
115+
char *osv_cmdline() {
116+
return str_to_c_str(osv::getcmdline());
117+
}
118+
119+
extern "C" OSV_MODULE_API
120+
char *osv_hypervisor_name() {
121+
return str_to_c_str(osv::hypervisor_name());
122+
}
123+
124+
extern "C" OSV_MODULE_API
125+
char *osv_firmware_vendor() {
126+
return str_to_c_str(osv::firmware_vendor());
127+
}
128+
129+
extern "C" OSV_MODULE_API
130+
char *osv_processor_features() {
131+
return str_to_c_str(processor::features_str());
132+
}
133+
134+
extern char debug_buffer[DEBUG_BUFFER_SIZE];
135+
extern "C" OSV_MODULE_API
136+
const char *osv_debug_buffer() {
137+
return debug_buffer;
138+
}
139+
140+
extern "C" OSV_MODULE_API
141+
void osv_current_app_on_termination_request(void (*handler)()) {
142+
osv::this_application::on_termination_request(handler);
143+
}
144+
145+
extern bool verbose;
146+
extern "C" OSV_MODULE_API
147+
bool osv_debug_enabled() {
148+
return verbose;
149+
}

include/osv/export.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232

3333
// This is to expose some symbols in libsolaris.so
3434
#define OSV_LIB_SOLARIS_API __attribute__((__visibility__("default")))
35+
//
36+
// This is to expose some OSv functions intended to be used by modules
37+
#define OSV_MODULE_API __attribute__((__visibility__("default")))
3538

3639
// In some very few cases, when source files are compiled without visibility
3740
// flag in order to expose most symbols in the corresponding file, there are some specific

include/osv/osv_c_wrappers.h

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,125 @@
88
#ifndef INCLUDED_OSV_C_WRAPPERS_H
99
#define INCLUDED_OSV_C_WRAPPERS_H
1010

11+
#include <limits.h>
1112
#include <sys/types.h>
13+
#include <osv/mount.h>
1214

1315
#ifdef __cplusplus
1416
extern "C" {
1517
#endif
1618

19+
// This C enum should be kept in sync with the C++ enum class
20+
// sched::thread::status defined in sched.hh
21+
enum osv_thread_status {
22+
invalid,
23+
prestarted,
24+
unstarted,
25+
waiting,
26+
sending_lock,
27+
running,
28+
queued,
29+
waking,
30+
terminating,
31+
terminated
32+
};
33+
34+
struct osv_thread {
35+
// 32-bit thread id
36+
long id;
37+
38+
// CPU the thread is running on
39+
long cpu_id;
40+
41+
// Total CPU time used by the thread (in milliseconds)
42+
long cpu_ms;
43+
44+
// Number of times this thread was context-switched in
45+
long switches;
46+
47+
// Number of times this thread was migrated between CPUs
48+
long migrations;
49+
50+
// Number of times this thread was preempted (still runnable, but switched out)
51+
long preemptions;
52+
53+
float priority;
54+
long stack_size;
55+
56+
enum osv_thread_status status;
57+
58+
// Thread name
59+
char* name;
60+
};
61+
1762
/*
1863
Save in *tid_arr array TIDs of all threads from app which "owns" input tid/thread.
19-
*tid_arr is allocated with malloc, *len holds lenght.
64+
*tid_arr is allocated with malloc, *len holds length.
2065
Caller is responsible to free tid_arr.
2166
Returns 0 on success, error code on error.
2267
*/
2368
int osv_get_all_app_threads(pid_t tid, pid_t** tid_arr, size_t* len);
2469

70+
/*
71+
Save in *thread_arr array info about all threads.
72+
*thread_arr is allocated with malloc, *len holds length.
73+
Caller is responsible to free thread_arr and thread names
74+
in osv_thread struct.
75+
Returns 0 on success, error code on error.
76+
*/
77+
int osv_get_all_threads(osv_thread** thread_arr, size_t *len);
78+
79+
/*
80+
* Return OSv version as C string. The returned C string is
81+
* allocated with malloc and caller is responsible to free it
82+
* if non null.
83+
*/
84+
char *osv_version();
85+
86+
/*
87+
* Return OSv command line C string. The returned C string is
88+
* allocated with malloc and caller is responsible to free it
89+
* if non null.
90+
*/
91+
char *osv_cmdline();
92+
93+
/*
94+
* Return hypervisor name as C string. The returned C string is
95+
* allocated with malloc and caller is responsible to free it
96+
* if non null.
97+
*/
98+
char *osv_hypervisor_name();
99+
100+
/*
101+
* Return firmware vendor as C string. The returned C string is
102+
* allocated with malloc and caller is responsible to free it
103+
* if non null.
104+
*/
105+
char *osv_firmware_vendor();
106+
107+
/*
108+
* Return processor features as C string. The returned C string is
109+
* allocated with malloc and caller is responsible to free it
110+
* if non null.
111+
*/
112+
char *osv_processor_features();
113+
114+
/*
115+
* Return pointer to OSv debug buffer.
116+
*/
117+
const char *osv_debug_buffer();
118+
119+
/*
120+
* Return true if OSv debug flag (--verbose) is enabled, otherwise return false.
121+
*/
122+
bool osv_debug_enabled();
123+
124+
/*
125+
* Pass a function pointer of a routine which will be invoked
126+
* upon termination of the current app. Useful for resources cleanup.
127+
*/
128+
void osv_current_app_on_termination_request(void (*handler)());
129+
25130
#ifdef __cplusplus
26131
}
27132
#endif

0 commit comments

Comments
 (0)