Skip to content

Commit 23c5e1f

Browse files
Merge branch 'proxy-wasm:master' into master
2 parents c8cec6b + 860f36a commit 23c5e1f

File tree

14 files changed

+300
-109
lines changed

14 files changed

+300
-109
lines changed

.github/workflows/cpp.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ jobs:
3535

3636
steps:
3737
- uses: actions/checkout@v2
38+
- uses: actions/setup-go@v2
39+
with:
40+
go-version: '^1.16'
3841

3942
- name: Format (clang-format)
4043
run: |
@@ -44,13 +47,13 @@ jobs:
4447
4548
- name: Format (buildifier)
4649
run: |
47-
go get -u github.com/bazelbuild/buildtools/buildifier
50+
go install github.com/bazelbuild/buildtools/buildifier@latest
4851
export PATH=$PATH:$(go env GOPATH)/bin
4952
find . -name "BUILD" | xargs -n1 buildifier -mode=check
5053
5154
- name: Format (addlicense)
5255
run: |
53-
go get -u github.com/google/addlicense
56+
go install github.com/google/addlicense@latest
5457
export PATH=$PATH:$(go env GOPATH)/bin
5558
addlicense -check .
5659

include/proxy-wasm/exports.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,36 @@ ::proxy_wasm::ContextBase *contextOrEffectiveContext();
3030

3131
extern thread_local ContextBase *current_context_;
3232

33+
/**
34+
* WasmForeignFunction is used for registering host-specific host functions.
35+
* A foreign function can be registered via RegisterForeignFunction and available
36+
* to Wasm modules via proxy_call_foreign_function.
37+
* @param wasm is the WasmBase which the Wasm module is running on.
38+
* @param argument is the view to the argument to the function passed by the module.
39+
* @param alloc_result is used to allocate the result data of this foreign function.
40+
*/
41+
using WasmForeignFunction = std::function<WasmResult(
42+
WasmBase &wasm, std::string_view argument, std::function<void *(size_t size)> alloc_result)>;
43+
44+
/**
45+
* Used to get the foreign function registered via RegisterForeignFunction for a given name.
46+
* @param function_name is the name used to lookup the foreign function table.
47+
* @return a WasmForeignFunction if registered.
48+
*/
49+
WasmForeignFunction getForeignFunction(std::string_view function_name);
50+
51+
/**
52+
* RegisterForeignFunction is used to register a foreign function in the lookup table
53+
* used internally in getForeignFunction.
54+
*/
55+
struct RegisterForeignFunction {
56+
/**
57+
* @param function_name is the key for this foreign function.
58+
* @param f is the function instance.
59+
*/
60+
RegisterForeignFunction(std::string function_name, WasmForeignFunction f);
61+
};
62+
3363
namespace exports {
3464

3565
template <typename Pairs> size_t pairsSize(const Pairs &result) {

include/proxy-wasm/wasm.h

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,8 @@ namespace proxy_wasm {
3434
#include "proxy_wasm_common.h"
3535

3636
class ContextBase;
37-
class WasmBase;
3837
class WasmHandleBase;
3938

40-
using WasmForeignFunction =
41-
std::function<WasmResult(WasmBase &, std::string_view, std::function<void *(size_t size)>)>;
4239
using WasmVmFactory = std::function<std::unique_ptr<WasmVm>()>;
4340
using CallOnThreadFunction = std::function<void(std::function<void()>)>;
4441

@@ -129,8 +126,6 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
129126
bool copyToPointerSize(std::string_view s, uint64_t ptr_ptr, uint64_t size_ptr);
130127
template <typename T> bool setDatatype(uint64_t ptr, const T &t);
131128

132-
WasmForeignFunction getForeignFunction(std::string_view function_name);
133-
134129
void fail(FailState fail_state, std::string_view message) {
135130
error(message);
136131
failed_ = fail_state;
@@ -176,6 +171,35 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
176171
uint32_t nextGaugeMetricId() { return next_gauge_metric_id_ += kMetricIdIncrement; }
177172
uint32_t nextHistogramMetricId() { return next_histogram_metric_id_ += kMetricIdIncrement; }
178173

174+
enum class CalloutType : uint32_t {
175+
HttpCall = 0,
176+
GrpcCall = 1,
177+
GrpcStream = 2,
178+
};
179+
static const uint32_t kCalloutTypeMask = 0x3; // Enough to cover the 3 types.
180+
static const uint32_t kCalloutIncrement = 0x4; // Enough to cover the 3 types.
181+
bool isHttpCallId(uint32_t callout_id) {
182+
return (callout_id & kCalloutTypeMask) == static_cast<uint32_t>(CalloutType::HttpCall);
183+
}
184+
bool isGrpcCallId(uint32_t callout_id) {
185+
return (callout_id & kCalloutTypeMask) == static_cast<uint32_t>(CalloutType::GrpcCall);
186+
}
187+
bool isGrpcStreamId(uint32_t callout_id) {
188+
return (callout_id & kCalloutTypeMask) == static_cast<uint32_t>(CalloutType::GrpcStream);
189+
}
190+
uint32_t nextHttpCallId() {
191+
// TODO(PiotrSikora): re-add rollover protection (requires at least 1 billion callouts).
192+
return next_http_call_id_ += kCalloutIncrement;
193+
}
194+
uint32_t nextGrpcCallId() {
195+
// TODO(PiotrSikora): re-add rollover protection (requires at least 1 billion callouts).
196+
return next_grpc_call_id_ += kCalloutIncrement;
197+
}
198+
uint32_t nextGrpcStreamId() {
199+
// TODO(PiotrSikora): re-add rollover protection (requires at least 1 billion callouts).
200+
return next_grpc_stream_id_ += kCalloutIncrement;
201+
}
202+
179203
protected:
180204
friend class ContextBase;
181205
class ShutdownHandle;
@@ -279,6 +303,11 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
279303
uint32_t next_gauge_metric_id_ = static_cast<uint32_t>(MetricType::Gauge);
280304
uint32_t next_histogram_metric_id_ = static_cast<uint32_t>(MetricType::Histogram);
281305

306+
// HTTP/gRPC callouts.
307+
uint32_t next_http_call_id_ = static_cast<uint32_t>(CalloutType::HttpCall);
308+
uint32_t next_grpc_call_id_ = static_cast<uint32_t>(CalloutType::GrpcCall);
309+
uint32_t next_grpc_stream_id_ = static_cast<uint32_t>(CalloutType::GrpcStream);
310+
282311
// Actions to be done after the call into the VM returns.
283312
std::deque<std::function<void()>> after_vm_call_actions_;
284313

@@ -405,8 +434,4 @@ template <typename T> inline bool WasmBase::setDatatype(uint64_t ptr, const T &t
405434
return wasm_vm_->setMemory(ptr, sizeof(T), &t);
406435
}
407436

408-
struct RegisterForeignFunction {
409-
RegisterForeignFunction(std::string name, WasmForeignFunction f);
410-
};
411-
412437
} // namespace proxy_wasm

include/proxy-wasm/wasm_vm.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <optional>
2121
#include <string>
2222
#include <unordered_map>
23+
#include <vector>
2324

2425
#include "include/proxy-wasm/word.h"
2526

@@ -176,8 +177,8 @@ class WasmVm {
176177
public:
177178
virtual ~WasmVm() = default;
178179
/**
179-
* Return the runtime identifier.
180-
* @return one of WasmRuntimeValues from well_known_names.h (e.g. "v8").
180+
* Identify the Wasm runtime.
181+
* @return the name of the underlying Wasm runtime.
181182
*/
182183
virtual std::string_view runtime() = 0;
183184

@@ -297,12 +298,12 @@ class WasmVm {
297298
void fail(FailState fail_state, std::string_view message) {
298299
integration()->error(message);
299300
failed_ = fail_state;
300-
if (fail_callback_) {
301-
fail_callback_(fail_state);
301+
for (auto &callback : fail_callbacks_) {
302+
callback(fail_state);
302303
}
303304
}
304-
void setFailCallback(std::function<void(FailState)> fail_callback) {
305-
fail_callback_ = fail_callback;
305+
void addFailCallback(std::function<void(FailState)> fail_callback) {
306+
fail_callbacks_.push_back(fail_callback);
306307
}
307308

308309
// Integrator operations.
@@ -312,7 +313,7 @@ class WasmVm {
312313
protected:
313314
std::unique_ptr<WasmVmIntegration> integration_;
314315
FailState failed_ = FailState::Ok;
315-
std::function<void(FailState)> fail_callback_;
316+
std::vector<std::function<void(FailState)>> fail_callbacks_;
316317
};
317318

318319
// Thread local state set during a call into a WASM VM so that calls coming out of the

src/exports.cc

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,24 @@ ContextBase *contextOrEffectiveContext() {
3636
// of current_context_.
3737
extern thread_local uint32_t effective_context_id_;
3838

39+
std::unordered_map<std::string, WasmForeignFunction> &foreignFunctions() {
40+
static auto ptr = new std::unordered_map<std::string, WasmForeignFunction>;
41+
return *ptr;
42+
}
43+
44+
WasmForeignFunction getForeignFunction(std::string_view function_name) {
45+
auto foreign_functions = foreignFunctions();
46+
auto it = foreign_functions.find(std::string(function_name));
47+
if (it != foreign_functions.end()) {
48+
return it->second;
49+
}
50+
return nullptr;
51+
}
52+
53+
RegisterForeignFunction::RegisterForeignFunction(std::string name, WasmForeignFunction f) {
54+
foreignFunctions()[name] = f;
55+
}
56+
3957
namespace exports {
4058

4159
namespace {
@@ -220,7 +238,7 @@ Word call_foreign_function(Word function_name, Word function_name_size, Word arg
220238
if (!args_opt) {
221239
return WasmResult::InvalidMemoryAccess;
222240
}
223-
auto f = context->wasm()->getForeignFunction(function.value());
241+
auto f = getForeignFunction(function.value());
224242
if (!f) {
225243
return WasmResult::NotFound;
226244
}

src/wasm.cc

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ thread_local std::unordered_map<std::string, std::weak_ptr<PluginHandleBase>> lo
4545
// Map from Wasm Key to the base Wasm instance, using a pointer to avoid the initialization fiasco.
4646
std::mutex base_wasms_mutex;
4747
std::unordered_map<std::string, std::weak_ptr<WasmHandleBase>> *base_wasms = nullptr;
48-
std::unordered_map<std::string, WasmForeignFunction> *foreign_functions = nullptr;
4948

5049
std::vector<uint8_t> Sha256(const std::vector<std::string_view> parts) {
5150
uint8_t sha256[SHA256_DIGEST_LENGTH];
@@ -85,13 +84,6 @@ class WasmBase::ShutdownHandle {
8584
std::shared_ptr<WasmBase> wasm_;
8685
};
8786

88-
RegisterForeignFunction::RegisterForeignFunction(std::string name, WasmForeignFunction f) {
89-
if (!foreign_functions) {
90-
foreign_functions = new std::remove_reference<decltype(*foreign_functions)>::type;
91-
}
92-
(*foreign_functions)[name] = f;
93-
}
94-
9587
void WasmBase::registerCallbacks() {
9688
#define _REGISTER(_fn) \
9789
wasm_vm_->registerCallback( \
@@ -208,7 +200,7 @@ WasmBase::WasmBase(const std::shared_ptr<WasmHandleBase> &base_wasm_handle, Wasm
208200
if (!wasm_vm_) {
209201
failed_ = FailState::UnableToCreateVm;
210202
} else {
211-
wasm_vm_->setFailCallback([this](FailState fail_state) { failed_ = fail_state; });
203+
wasm_vm_->addFailCallback([this](FailState fail_state) { failed_ = fail_state; });
212204
}
213205
}
214206

@@ -222,7 +214,7 @@ WasmBase::WasmBase(std::unique_ptr<WasmVm> wasm_vm, std::string_view vm_id,
222214
if (!wasm_vm_) {
223215
failed_ = FailState::UnableToCreateVm;
224216
} else {
225-
wasm_vm_->setFailCallback([this](FailState fail_state) { failed_ = fail_state; });
217+
wasm_vm_->addFailCallback([this](FailState fail_state) { failed_ = fail_state; });
226218
}
227219
}
228220

@@ -454,14 +446,6 @@ void WasmBase::finishShutdown() {
454446
}
455447
}
456448

457-
WasmForeignFunction WasmBase::getForeignFunction(std::string_view function_name) {
458-
auto it = foreign_functions->find(std::string(function_name));
459-
if (it != foreign_functions->end()) {
460-
return it->second;
461-
}
462-
return nullptr;
463-
}
464-
465449
std::shared_ptr<WasmHandleBase> createWasm(std::string vm_key, std::string code,
466450
std::shared_ptr<PluginBase> plugin,
467451
WasmHandleFactory factory,
@@ -559,6 +543,14 @@ getOrCreateThreadLocalWasm(std::shared_ptr<WasmHandleBase> base_handle,
559543
return nullptr;
560544
}
561545
local_wasms[vm_key] = wasm_handle;
546+
wasm_handle->wasm()->wasm_vm()->addFailCallback([vm_key](proxy_wasm::FailState fail_state) {
547+
if (fail_state == proxy_wasm::FailState::RuntimeError) {
548+
// If VM failed, erase the entry so that:
549+
// 1) we can recreate the new thread local VM from the same base_wasm.
550+
// 2) we wouldn't reuse the failed VM for new plugins accidentally.
551+
local_wasms.erase(vm_key);
552+
};
553+
});
562554
return wasm_handle;
563555
}
564556

@@ -594,6 +586,14 @@ std::shared_ptr<PluginHandleBase> getOrCreateThreadLocalPlugin(
594586
}
595587
auto plugin_handle = plugin_factory(wasm_handle, plugin);
596588
local_plugins[key] = plugin_handle;
589+
wasm_handle->wasm()->wasm_vm()->addFailCallback([key](proxy_wasm::FailState fail_state) {
590+
if (fail_state == proxy_wasm::FailState::RuntimeError) {
591+
// If VM failed, erase the entry so that:
592+
// 1) we can recreate the new thread local plugin from the same base_wasm.
593+
// 2) we wouldn't reuse the failed VM for new plugin configs accidentally.
594+
local_plugins.erase(key);
595+
};
596+
});
597597
return plugin_handle;
598598
}
599599

test/BUILD

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,13 @@ cc_test(
7878
)
7979

8080
cc_test(
81-
name = "context_test",
82-
srcs = ["context_test.cc"],
81+
name = "wasm_test",
82+
srcs = ["wasm_test.cc"],
83+
data = [
84+
"//test/test_data:abi_export.wasm",
85+
],
8386
deps = [
87+
":utility_lib",
8488
"//:lib",
8589
"@com_google_googletest//:gtest",
8690
"@com_google_googletest//:gtest_main",

test/bytecode_util_test.cc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,14 @@ TEST(TestBytecodeUtil, getFunctionNameIndex) {
5959
// OK.
6060
EXPECT_TRUE(BytecodeUtil::getFunctionNameIndex(source, actual));
6161
EXPECT_FALSE(actual.empty());
62-
EXPECT_EQ(actual.find(0)->second, "proxy_abi_version_0_2_0");
62+
bool abi_version_found = false;
63+
for (auto it : actual) {
64+
if (it.second == "proxy_abi_version_0_2_0") {
65+
abi_version_found = true;
66+
break;
67+
}
68+
}
69+
EXPECT_TRUE(abi_version_found);
6370

6471
// Fail due to the corrupted bytecode.
6572
// TODO(@mathetake): here we haven't covered all the parsing failure branches. Add more cases.

test/context_test.cc

Lines changed: 0 additions & 35 deletions
This file was deleted.

0 commit comments

Comments
 (0)