Skip to content

Commit 1de015a

Browse files
authored
Enable onForeignFunction and proxy-specific extensions to the ABI. (#23)
* Enable onForeignFunction and proxy-specific extensions to the ABI. Signed-off-by: John Plevyak <jplevyak@gmail.com>
1 parent f25f824 commit 1de015a

13 files changed

+225
-93
lines changed

WORKSPACE

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
55

66
git_repository(
77
name = "proxy_wasm_cpp_sdk",
8-
commit = "f44562520bca7bfeee77d6284a96d2900f2f13ac",
8+
commit = "35163bbf32fccfbde7b95d909a392dc1dc562596",
99
remote = "https://github.com/proxy-wasm/proxy-wasm-cpp-sdk",
1010
)
1111

include/proxy-wasm/context.h

+68-12
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,46 @@ struct PluginBase {
6363
std::string log_prefix_;
6464
};
6565

66+
struct BufferBase : public BufferInterface {
67+
BufferBase() = default;
68+
~BufferBase() override = default;
69+
70+
// BufferInterface
71+
size_t size() const override {
72+
if (owned_data_) {
73+
return owned_data_size_;
74+
}
75+
return data_.size();
76+
}
77+
WasmResult copyTo(WasmBase *wasm, size_t start, size_t length, uint64_t ptr_ptr,
78+
uint64_t size_ptr) const override;
79+
WasmResult copyFrom(size_t /* start */, size_t /* length */, string_view /* data */) override {
80+
// Setting a string buffer not supported (no use case).
81+
return WasmResult::BadArgument;
82+
}
83+
84+
virtual void clear() {
85+
data_ = "";
86+
owned_data_ = nullptr;
87+
}
88+
BufferBase *set(string_view data) {
89+
clear();
90+
data_ = data;
91+
return this;
92+
}
93+
BufferBase *set(std::unique_ptr<char[]> owned_data, uint32_t owned_data_size) {
94+
clear();
95+
owned_data_ = std::move(owned_data);
96+
owned_data_size_ = owned_data_size;
97+
return this;
98+
}
99+
100+
protected:
101+
string_view data_;
102+
std::unique_ptr<char[]> owned_data_;
103+
uint32_t owned_data_size_;
104+
};
105+
66106
/**
67107
* ContextBase is the interface between the VM host and the VM. It has several uses:
68108
*
@@ -94,7 +134,7 @@ class ContextBase : public RootInterface,
94134
ContextBase(); // Testing.
95135
ContextBase(WasmBase *wasm); // Vm Context.
96136
ContextBase(WasmBase *wasm, std::shared_ptr<PluginBase> plugin); // Root Context.
97-
ContextBase(WasmBase *wasm, uint32_t root_context_id,
137+
ContextBase(WasmBase *wasm, uint32_t parent_context_id,
98138
std::shared_ptr<PluginBase> plugin); // Stream context.
99139
virtual ~ContextBase();
100140

@@ -103,8 +143,17 @@ class ContextBase : public RootInterface,
103143
// The VM Context used for calling "malloc" has an id_ == 0.
104144
bool isVmContext() const { return id_ == 0; }
105145
// Root Contexts have the VM Context as a parent.
106-
bool isRootContext() const { return root_context_id_ == 0; }
107-
ContextBase *root_context() const { return root_context_; }
146+
bool isRootContext() const { return parent_context_id_ == 0; }
147+
ContextBase *parent_context() const { return parent_context_; }
148+
ContextBase *root_context() const {
149+
const ContextBase *previous = this;
150+
ContextBase *parent = parent_context_;
151+
while (parent != previous) {
152+
previous = parent;
153+
parent = parent->parent_context_;
154+
}
155+
return parent;
156+
}
108157
string_view root_id() const { return isRootContext() ? root_id_ : plugin_->root_id_; }
109158
string_view log_prefix() const {
110159
return isRootContext() ? root_log_prefix_ : plugin_->log_prefix();
@@ -121,10 +170,11 @@ class ContextBase : public RootInterface,
121170
*/
122171

123172
// Context
124-
void onCreate(uint32_t parent_context_id) override;
173+
void onCreate() override;
125174
bool onDone() override;
126175
void onLog() override;
127176
void onDelete() override;
177+
void onForeignFunction(uint32_t foreign_function_id, uint32_t data_size) override;
128178

129179
// Root
130180
bool onStart(std::shared_ptr<PluginBase> plugin) override;
@@ -173,10 +223,6 @@ class ContextBase : public RootInterface,
173223
WasmResult log(uint32_t /* level */, string_view /* message */) override {
174224
return unimplemented();
175225
}
176-
WasmResult setTimerPeriod(std::chrono::milliseconds /* period */,
177-
uint32_t * /* timer_token_ptr */) override {
178-
return unimplemented();
179-
}
180226
uint64_t getCurrentTimeNanoseconds() override {
181227
struct timespec tpe;
182228
clock_gettime(CLOCK_REALTIME, &tpe);
@@ -189,6 +235,7 @@ class ContextBase : public RootInterface,
189235
unimplemented();
190236
return std::make_pair(1, "unimplmemented");
191237
}
238+
WasmResult setTimerPeriod(std::chrono::milliseconds period, uint32_t *timer_token_ptr) override;
192239

193240
// Buffer
194241
BufferInterface *getBuffer(WasmBufferType /* type */) override {
@@ -316,15 +363,24 @@ class ContextBase : public RootInterface,
316363

317364
WasmBase *wasm_{nullptr};
318365
uint32_t id_{0};
319-
uint32_t root_context_id_{0}; // 0 for roots and the general context.
320-
ContextBase *root_context_{nullptr}; // set in all contexts.
321-
std::string root_id_; // set only in root context.
322-
std::string root_log_prefix_; // set only in root context.
366+
uint32_t parent_context_id_{0}; // 0 for roots and the general context.
367+
ContextBase *parent_context_{nullptr}; // set in all contexts.
368+
std::string root_id_; // set only in root context.
369+
std::string root_log_prefix_; // set only in root context.
323370
std::shared_ptr<PluginBase> plugin_;
324371
bool in_vm_context_created_ = false;
325372
bool destroyed_ = false;
326373
};
327374

375+
class DeferAfterCallActions {
376+
public:
377+
DeferAfterCallActions(ContextBase *context) : wasm_(context->wasm()) {}
378+
~DeferAfterCallActions();
379+
380+
private:
381+
WasmBase *const wasm_;
382+
};
383+
328384
uint32_t resolveQueueForTest(string_view vm_id, string_view queue_name);
329385

330386
} // namespace proxy_wasm

include/proxy-wasm/context_interface.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,9 @@ struct RootInterface : public RootGrpcInterface {
133133
/**
134134
* Call on a host Context to create a corresponding Context in the VM. Note:
135135
* onNetworkNewConnection and onRequestHeaders() call onCreate().
136-
* @param parent_context_id is the parent Context id for the context being created. For a
137136
* stream Context this will be a Root Context id (or sub-Context thereof).
138137
*/
139-
virtual void onCreate(uint32_t parent_context_id) = 0;
138+
virtual void onCreate() = 0;
140139

141140
/**
142141
* Call on a Root Context when a VM first starts up.
@@ -564,6 +563,15 @@ struct GeneralInterface {
564563
* serialized..
565564
*/
566565
virtual WasmResult setProperty(string_view key, string_view value) = 0;
566+
567+
/**
568+
* Custom extension call into the VM. Data is provided as WasmBufferType::CallData.
569+
* @param foreign_function_id a unique identifier for the calling foreign function. These are
570+
* defined and allocated by the foreign function implementor.
571+
* @param data_size is the size of the WasmBufferType::CallData buffer containing data for this
572+
* foreign function call.
573+
*/
574+
virtual void onForeignFunction(uint32_t foreign_function_id, uint32_t data_size) = 0;
567575
};
568576

569577
/**

include/proxy-wasm/exports.h

+10
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
#include "include/proxy-wasm/word.h"
2121

2222
namespace proxy_wasm {
23+
24+
class ContextBase;
25+
26+
extern thread_local ContextBase *current_context_;
27+
2328
namespace exports {
2429

2530
// ABI functions exported from envoy to wasm.
@@ -107,5 +112,10 @@ void wasi_unstable_proc_exit(void *, Word);
107112
void wasi_unstable_proc_exit(void *, Word);
108113
Word pthread_equal(void *, Word left, Word right);
109114

115+
// Support for embedders, not exported to Wasm.
116+
117+
// Any currently executing Wasm call context.
118+
::proxy_wasm::ContextBase *ContextOrEffectiveContext(::proxy_wasm::ContextBase *context);
119+
110120
} // namespace exports
111121
} // namespace proxy_wasm

include/proxy-wasm/null_plugin.h

+8-6
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,19 @@
2020
#include "google/protobuf/message.h"
2121
#include "include/proxy-wasm/null_vm_plugin.h"
2222
#include "include/proxy-wasm/wasm.h"
23+
#include "include/proxy-wasm/exports.h"
2324

2425
namespace proxy_wasm {
2526
namespace null_plugin {
27+
template <typename T> using Optional = optional<T>;
28+
using StringView = string_view;
2629
#include "proxy_wasm_enums.h"
2730
} // namespace null_plugin
2831
} // namespace proxy_wasm
2932

3033
#include "include/proxy-wasm/wasm_api_impl.h"
3134

3235
namespace proxy_wasm {
33-
namespace null_plugin {
34-
using StringView = string_view;
35-
template <typename T> using Optional = optional<T>;
36-
#include "proxy_wasm_api.h"
37-
} // namespace null_plugin
3836

3937
/**
4038
* Registry for Plugin implementation.
@@ -48,6 +46,8 @@ struct NullPluginRegistry {
4846
uint32_t (*proxy_on_configure_)(uint32_t root_context_id,
4947
uint32_t plugin_configuration_size) = nullptr;
5048
void (*proxy_on_tick_)(uint32_t context_id) = nullptr;
49+
void (*proxy_on_foreign_function_)(uint32_t context_id, uint32_t token,
50+
uint32_t data_size) = nullptr;
5151
uint32_t (*proxy_on_done_)(uint32_t context_id) = nullptr;
5252
void (*proxy_on_delete_)(uint32_t context_id) = nullptr;
5353
std::unordered_map<std::string, null_plugin::RootFactory> root_factories;
@@ -74,6 +74,8 @@ class NullPlugin : public NullVmPlugin {
7474
bool onConfigure(uint64_t root_context_id, uint64_t plugin_configuration_size);
7575
void onTick(uint64_t root_context_id);
7676
void onQueueReady(uint64_t root_context_id, uint64_t token);
77+
void onForeignFunction(uint64_t root_context_id, uint64_t foreign_function_id,
78+
uint64_t data_size);
7779

7880
void onCreate(uint64_t context_id, uint64_t root_context_id);
7981

@@ -110,12 +112,12 @@ class NullPlugin : public NullVmPlugin {
110112

111113
void error(string_view message) { wasm_vm_->error(message); }
112114

113-
private:
114115
null_plugin::Context *ensureContext(uint64_t context_id, uint64_t root_context_id);
115116
null_plugin::RootContext *ensureRootContext(uint64_t context_id);
116117
null_plugin::RootContext *getRootContext(uint64_t context_id);
117118
null_plugin::ContextBase *getContextBase(uint64_t context_id);
118119

120+
private:
119121
NullPluginRegistry *registry_{};
120122
std::unordered_map<std::string, null_plugin::RootContext *> root_context_map_;
121123
std::unordered_map<int64_t, std::unique_ptr<null_plugin::ContextBase>> context_map_;

include/proxy-wasm/wasm.h

+25-22
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,17 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
7676
const std::string &vm_configuration() const;
7777
bool allow_precompiled() const { return allow_precompiled_; }
7878

79+
void timerReady(uint32_t root_context_id);
80+
void queueReady(uint32_t root_context_id, uint32_t token);
81+
82+
void startShutdown();
83+
WasmResult done(ContextBase *root_context);
84+
void finishShutdown();
85+
86+
// Proxy specific extension points.
87+
//
88+
virtual void registerCallbacks(); // Register functions called out from Wasm.
89+
virtual void getFunctions(); // Get functions call into Wasm.
7990
virtual CallOnThreadFunction callOnThreadFunction() {
8091
unimplemented();
8192
return nullptr;
@@ -86,18 +97,17 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
8697
return new ContextBase(this, plugin);
8798
return new ContextBase(this);
8899
}
89-
90-
virtual void setTickPeriod(uint32_t root_context_id, std::chrono::milliseconds tick_period) {
91-
tick_period_[root_context_id] = tick_period;
100+
virtual void setTimerPeriod(uint32_t root_context_id, std::chrono::milliseconds period) {
101+
timer_period_[root_context_id] = period;
92102
}
93-
void tick(uint32_t root_context_id);
94-
void queueReady(uint32_t root_context_id, uint32_t token);
95-
96-
void startShutdown();
97-
WasmResult done(ContextBase *root_context);
98-
void finishShutdown();
103+
virtual void error(string_view message) {
104+
std::cerr << message << "\n";
105+
abort();
106+
}
107+
virtual void unimplemented() { error("unimplemented proxy-wasm API"); }
99108

100109
// Support functions.
110+
//
101111
void *allocMemory(uint64_t size, uint64_t *address);
102112
// Allocate a null-terminated string in the VM and return the pointer to use as a call arguments.
103113
uint64_t copyString(string_view s);
@@ -107,14 +117,9 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
107117

108118
WasmForeignFunction getForeignFunction(string_view function_name);
109119

110-
virtual void error(string_view message) {
111-
std::cerr << message << "\n";
112-
abort();
113-
}
114-
virtual void unimplemented() { error("unimplemented proxy-wasm API"); }
115-
116120
// For testing.
117-
void setContext(ContextBase *context) { contexts_[context->id()] = context; }
121+
//
122+
void setContextForTesting(ContextBase *context) { contexts_[context->id()] = context; }
118123
// Returns false if onStart returns false.
119124
bool startForTesting(std::unique_ptr<ContextBase> root_context,
120125
std::shared_ptr<PluginBase> plugin);
@@ -146,8 +151,6 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
146151
}
147152
}
148153

149-
// These are the same as the values of the MetricType enum, here separately for
150-
// convenience.
151154
static const uint32_t kMetricTypeMask = 0x3; // Enough to cover the 3 types.
152155
static const uint32_t kMetricIdIncrement = 0x4; // Enough to cover the 3 types.
153156
bool isCounterMetricId(uint32_t metric_id) {
@@ -166,9 +169,8 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
166169
protected:
167170
friend class ContextBase;
168171
class ShutdownHandle;
169-
void registerCallbacks(); // Register functions called out from WASM.
172+
170173
void establishEnvironment(); // Language specific environments.
171-
void getFunctions(); // Get functions call into WASM.
172174

173175
std::string vm_id_; // User-provided vm_id.
174176
std::string vm_key_; // vm_id + hash of code.
@@ -179,8 +181,8 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
179181
std::shared_ptr<ContextBase> vm_context_; // Context unrelated to any specific root or stream
180182
// (e.g. for global constructors).
181183
std::unordered_map<std::string, std::unique_ptr<ContextBase>> root_contexts_;
182-
std::unordered_map<uint32_t, ContextBase *> contexts_; // Contains all contexts.
183-
std::unordered_map<uint32_t, std::chrono::milliseconds> tick_period_; // per root_id.
184+
std::unordered_map<uint32_t, ContextBase *> contexts_; // Contains all contexts.
185+
std::unordered_map<uint32_t, std::chrono::milliseconds> timer_period_; // per root_id.
184186
std::unique_ptr<ShutdownHandle> shutdown_handle_;
185187
std::unordered_set<ContextBase *> pending_done_; // Root contexts not done during shutdown.
186188

@@ -224,6 +226,7 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
224226
WasmCallVoid<3> on_grpc_receive_trailing_metadata_;
225227

226228
WasmCallVoid<2> on_queue_ready_;
229+
WasmCallVoid<3> on_foreign_function_;
227230

228231
WasmCallWord<1> on_done_;
229232
WasmCallVoid<1> on_log_;

include/proxy-wasm/wasm_api_impl.h

+4-10
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,6 @@
1818
#include "include/proxy-wasm/compat.h"
1919

2020
namespace proxy_wasm {
21-
namespace null_plugin {
22-
class RootContext;
23-
class Context;
24-
} // namespace null_plugin
25-
26-
null_plugin::RootContext *nullVmGetRoot(string_view root_id);
27-
null_plugin::Context *nullVmGetContext(uint32_t context_id);
28-
2921
namespace null_plugin {
3022

3123
#define WS(_x) Word(static_cast<uint64_t>(_x))
@@ -264,8 +256,10 @@ inline WasmResult proxy_call_foreign_function(const char *function_name, size_t
264256
#undef WS
265257
#undef WR
266258

267-
inline RootContext *getRoot(string_view root_id) { return nullVmGetRoot(root_id); }
268-
inline Context *getContext(uint32_t context_id) { return nullVmGetContext(context_id); }
259+
#include "proxy_wasm_api.h"
260+
261+
RootContext *getRoot(string_view root_id);
262+
Context *getContext(uint32_t context_id);
269263

270264
} // namespace null_plugin
271265
} // namespace proxy_wasm

0 commit comments

Comments
 (0)