Skip to content

Commit d55f8de

Browse files
committed
Impleplement support in metacall_load_from_{file, memory, package}, for passing handle as in parameter, refactor extension interfaces in order to support handles and propagate symbols to existing handle being loaded by the extension.
1 parent 3cccab9 commit d55f8de

File tree

12 files changed

+122
-47
lines changed

12 files changed

+122
-47
lines changed

source/extensions/plugin_extension/include/plugin_extension/plugin_extension.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
extern "C" {
3030
#endif
3131

32-
PLUGIN_EXTENSION_API int plugin_extension(void *loader, void *context);
32+
PLUGIN_EXTENSION_API int plugin_extension(void *loader, void *handle, void *context);
3333

3434
DYNLINK_SYMBOL_EXPORT(plugin_extension);
3535

source/extensions/plugin_extension/source/plugin_extension.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,13 @@ static int plugin_extension_get_path(std::string &ext_path)
6767
return 0;
6868
}
6969

70-
int plugin_extension(void *, void *)
70+
int plugin_extension(void *loader, void *handle, void *context)
7171
{
7272
std::string ext_path;
7373

74+
(void)loader;
75+
(void)context;
76+
7477
if (plugin_extension_get_path(ext_path) != 0)
7578
{
7679
log_write("metacall", LOG_LEVEL_ERROR, "Define the extension path with the environment variable " METACALL_PLUGIN_PATH);
@@ -102,7 +105,7 @@ int plugin_extension(void *, void *)
102105
{
103106
log_write("metacall", LOG_LEVEL_DEBUG, "Loading extension: %s", dir.path().filename().c_str());
104107

105-
if (metacall_load_from_configuration(dir.path().c_str(), NULL, config_allocator) != 0)
108+
if (metacall_load_from_configuration(dir.path().c_str(), &handle, config_allocator) != 0)
106109
{
107110
log_write("metacall", LOG_LEVEL_ERROR, "Failed to load extension: %s", dir.path().c_str());
108111
return 1;

source/loader/include/loader/loader_impl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ LOADER_API value loader_impl_handle_export(void *handle);
7575

7676
LOADER_API context loader_impl_handle_context(void *handle);
7777

78+
LOADER_API void *loader_impl_handle_container_of(void *impl);
79+
7880
LOADER_API int loader_impl_handle_validate(void *handle);
7981

8082
LOADER_API value loader_impl_metadata(loader_impl impl);

source/loader/source/loader_impl.c

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,7 @@ loader_handle_impl loader_impl_load_handle(loader_impl impl, loader_impl_interfa
519519
{
520520
handle_impl->magic = (uintptr_t)loader_handle_impl_magic_free;
521521
free(handle_impl);
522+
return NULL;
522523
}
523524

524525
handle_impl->magic = (uintptr_t)loader_handle_impl_magic_alloc;
@@ -671,6 +672,7 @@ int loader_impl_handle_register_cb_iterate(plugin_manager manager, plugin p, voi
671672

672673
int loader_impl_handle_register(plugin_manager manager, loader_impl impl, const char *path, loader_handle_impl handle_impl, void **handle_ptr)
673674
{
675+
/* If there's no handle input/output pointer passed as input parameter, then propagate the handle symbols to the loader context */
674676
if (handle_ptr == NULL)
675677
{
676678
/* This case handles the global scope (shared scope between all loaders, there is no out reference to a handle) */
@@ -694,7 +696,27 @@ int loader_impl_handle_register(plugin_manager manager, loader_impl impl, const
694696
}
695697
else
696698
{
697-
return loader_impl_handle_init(impl, path, handle_impl, handle_ptr, 1);
699+
/* Otherwise, if there's a handle pointer and it is different from NULL, it means we are passing a handle as input parameter, so propagate symbols to this handle */
700+
if (*handle_ptr != NULL)
701+
{
702+
loader_handle_impl target_handle = (loader_handle_impl)*handle_ptr;
703+
char *duplicated_key;
704+
705+
if (context_contains(handle_impl->ctx, target_handle->ctx, &duplicated_key) == 0 && duplicated_key != NULL)
706+
{
707+
log_write("metacall", LOG_LEVEL_ERROR, "Duplicated symbol found named '%s' already defined in the handle scope by handle: %s", duplicated_key, path);
708+
return 1;
709+
}
710+
else if (context_append(impl->ctx, handle_impl->ctx) == 0)
711+
{
712+
return loader_impl_handle_init(impl, path, handle_impl, NULL, 1);
713+
}
714+
}
715+
else
716+
{
717+
/* Otherwise, initialize the handle and do not propagate the symbols, keep it private to the handle instance */
718+
return loader_impl_handle_init(impl, path, handle_impl, handle_ptr, 1);
719+
}
698720
}
699721

700722
return 1;
@@ -997,6 +1019,16 @@ context loader_impl_handle_context(void *handle)
9971019
return handle_impl->ctx;
9981020
}
9991021

1022+
void *loader_impl_handle_container_of(void *impl)
1023+
{
1024+
loader_handle handle = impl;
1025+
1026+
#define container_of(ptr, type, member) \
1027+
(type *)((char *)(ptr) - (char *)&((type *)0)->member)
1028+
1029+
return container_of(handle, struct loader_handle_impl_type, module);
1030+
}
1031+
10001032
int loader_impl_handle_validate(void *handle)
10011033
{
10021034
loader_handle_impl handle_impl = handle;

source/loaders/ext_loader/source/ext_loader_impl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ typedef struct loader_impl_ext_handle_type
6262
union loader_impl_function_cast
6363
{
6464
void *ptr;
65-
int (*fn)(void *, void *);
65+
int (*fn)(void *, void *, void *);
6666
};
6767

6868
dynlink ext_loader_impl_load_from_file_dynlink(loader_impl_ext ext_impl, const loader_path path);
@@ -296,7 +296,7 @@ int ext_loader_impl_discover(loader_impl impl, loader_handle handle, context ctx
296296

297297
function_cast.ptr = static_cast<void *>(ext.addr);
298298

299-
if (function_cast.fn(impl, ctx) != 0)
299+
if (function_cast.fn(impl, loader_impl_handle_container_of(handle), ctx) != 0)
300300
{
301301
return 1;
302302
}

source/metacall/include/metacall/metacall.h

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,14 @@ METACALL_API int metacall_execution_path_s(const char *tag, size_t tag_length, c
238238
* @param[in] size
239239
* Size of the array @paths
240240
*
241-
* @param[out] handle
242-
* Optional pointer to reference of loaded handle
241+
* @param[inout] handle
242+
* Optional pointer to reference of loaded handle. If the parameter is NULL, the symbols loaded are
243+
* propagated to the loader scope (i.e they will share the scope between all previously loaded files and they can collide).
244+
* Otherwise, if we pass a void* pointer set to NULL, it will behave as output parameter, obtaining the reference to the
245+
* created handle, which can be later on used for calling to functions of that handle. The symbols will not be propagated
246+
* to the loader scope and they will be private (this prevents collisions). The last case is if we pass an already allocated
247+
* handle (i.e a void* pointer pointing to an previously loaded handle), then in this case, the symbols loaded will be propagated
248+
* to the previously allocated handle, and it will behave as a in parameter.
243249
*
244250
* @return
245251
* Zero if success, different from zero otherwise
@@ -259,8 +265,14 @@ METACALL_API int metacall_load_from_file(const char *tag, const char *paths[], s
259265
* @param[in] size
260266
* Memory block representing the string of the script
261267
*
262-
* @param[out] handle
263-
* Optional pointer to reference of loaded handle
268+
* @param[inout] handle
269+
* Optional pointer to reference of loaded handle. If the parameter is NULL, the symbols loaded are
270+
* propagated to the loader scope (i.e they will share the scope between all previously loaded files and they can collide).
271+
* Otherwise, if we pass a void* pointer set to NULL, it will behave as output parameter, obtaining the reference to the
272+
* created handle, which can be later on used for calling to functions of that handle. The symbols will not be propagated
273+
* to the loader scope and they will be private (this prevents collisions). The last case is if we pass an already allocated
274+
* handle (i.e a void* pointer pointing to an previously loaded handle), then in this case, the symbols loaded will be propagated
275+
* to the previously allocated handle, and it will behave as a in parameter.
264276
*
265277
* @return
266278
* Zero if success, different from zero otherwise
@@ -277,8 +289,14 @@ METACALL_API int metacall_load_from_memory(const char *tag, const char *buffer,
277289
* @param[in] path
278290
* Path of the package
279291
*
280-
* @param[out] handle
281-
* Optional pointer to reference of loaded handle
292+
* @param[inout] handle
293+
* Optional pointer to reference of loaded handle. If the parameter is NULL, the symbols loaded are
294+
* propagated to the loader scope (i.e they will share the scope between all previously loaded files and they can collide).
295+
* Otherwise, if we pass a void* pointer set to NULL, it will behave as output parameter, obtaining the reference to the
296+
* created handle, which can be later on used for calling to functions of that handle. The symbols will not be propagated
297+
* to the loader scope and they will be private (this prevents collisions). The last case is if we pass an already allocated
298+
* handle (i.e a void* pointer pointing to an previously loaded handle), then in this case, the symbols loaded will be propagated
299+
* to the previously allocated handle, and it will behave as a in parameter.
282300
*
283301
* @return
284302
* Zero if success, different from zero otherwise
@@ -298,8 +316,14 @@ METACALL_API int metacall_load_from_package(const char *tag, const char *path, v
298316
* @param[in] path
299317
* Path of the configuration
300318
*
301-
* @param[out] handle
302-
* Optional pointer to reference of loaded handle
319+
* @param[inout] handle
320+
* Optional pointer to reference of loaded handle. If the parameter is NULL, the symbols loaded are
321+
* propagated to the loader scope (i.e they will share the scope between all previously loaded files and they can collide).
322+
* Otherwise, if we pass a void* pointer set to NULL, it will behave as output parameter, obtaining the reference to the
323+
* created handle, which can be later on used for calling to functions of that handle. The symbols will not be propagated
324+
* to the loader scope and they will be private (this prevents collisions). The last case is if we pass an already allocated
325+
* handle (i.e a void* pointer pointing to an previously loaded handle), then in this case, the symbols loaded will be propagated
326+
* to the previously allocated handle, and it will behave as a in parameter.
303327
*
304328
* @param[in] allocator
305329
* Pointer to allocator will allocate the configuration

source/scripts/extension/sum_extension/include/sum_extension/sum_extension.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
extern "C" {
3030
#endif
3131

32-
SUM_EXTENSION_API int sum_extension(void *loader, void *context);
32+
SUM_EXTENSION_API int sum_extension(void *loader, void *handle, void *context);
3333

3434
DYNLINK_SYMBOL_EXPORT(sum_extension);
3535

source/scripts/extension/sum_extension/source/sum_extension.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ void *sum(size_t argc, void *args[], void *data)
3434
return metacall_value_create_long(result);
3535
}
3636

37-
int sum_extension(void *loader, void *context)
37+
int sum_extension(void *loader, void *handle, void *context)
3838
{
3939
enum metacall_value_id arg_types[] = { METACALL_LONG, METACALL_LONG };
40+
(void)handle;
4041
return metacall_register_loaderv(loader, context, "sum", sum, METACALL_LONG, sizeof(arg_types) / sizeof(arg_types[0]), arg_types);
4142
}

source/tests/metacall_ext_test/source/metacall_ext_test.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,15 @@ TEST_F(metacall_ext_test, DefaultConstructor)
3535
const char *ext_scripts[] = {
3636
"sum_extension" /* The library extension (dll, so, dylib) is crossplatform so we should not add it here */
3737
};
38+
3839
void *handle = NULL;
40+
41+
/* Test reload of the extension */
3942
EXPECT_EQ((int)0, (int)metacall_load_from_file("ext", ext_scripts, sizeof(ext_scripts) / sizeof(ext_scripts[0]), &handle));
43+
4044
EXPECT_EQ((int)0, (int)metacall_clear(handle));
4145

46+
/* Test extension load and call */
4247
EXPECT_EQ((int)0, (int)metacall_load_from_file("ext", ext_scripts, sizeof(ext_scripts) / sizeof(ext_scripts[0]), NULL));
4348

4449
void *ret = metacall("sum", 3, 4);

source/tests/metacall_handle_get_test/source/metacall_handle_get_test.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -99,17 +99,17 @@ TEST_F(metacall_handle_get_test, DefaultConstructor)
9999
"s1.py"
100100
};
101101

102-
void *handle = NULL;
102+
void *handle1 = NULL;
103103

104-
EXPECT_EQ((int)0, (int)metacall_load_from_file("py", py_scripts_s1, sizeof(py_scripts_s1) / sizeof(py_scripts_s1[0]), &handle));
104+
EXPECT_EQ((int)0, (int)metacall_load_from_file("py", py_scripts_s1, sizeof(py_scripts_s1) / sizeof(py_scripts_s1[0]), &handle1));
105105

106-
ASSERT_NE((void *)NULL, (void *)handle);
106+
ASSERT_NE((void *)NULL, (void *)handle1);
107107

108-
void *func = metacall_handle_function(handle, "shared_in_s1_and_s2");
108+
void *func = metacall_handle_function(handle1, "shared_in_s1_and_s2");
109109

110110
ASSERT_NE((void *)NULL, (void *)func);
111111

112-
void *ret = metacallhv_s(handle, "shared_in_s1_and_s2", metacall_null_args, 0);
112+
void *ret = metacallhv_s(handle1, "shared_in_s1_and_s2", metacall_null_args, 0);
113113

114114
EXPECT_NE((void *)NULL, (void *)ret);
115115

@@ -121,15 +121,17 @@ TEST_F(metacall_handle_get_test, DefaultConstructor)
121121
"s2.py"
122122
};
123123

124-
EXPECT_EQ((int)0, (int)metacall_load_from_file("py", py_scripts_s2, sizeof(py_scripts_s2) / sizeof(py_scripts_s2[0]), &handle));
124+
void *handle2 = NULL;
125125

126-
ASSERT_NE((void *)NULL, (void *)handle);
126+
EXPECT_EQ((int)0, (int)metacall_load_from_file("py", py_scripts_s2, sizeof(py_scripts_s2) / sizeof(py_scripts_s2[0]), &handle2));
127+
128+
ASSERT_NE((void *)NULL, (void *)handle2);
127129

128-
func = metacall_handle_function(handle, "shared_in_s1_and_s2");
130+
func = metacall_handle_function(handle2, "shared_in_s1_and_s2");
129131

130132
ASSERT_NE((void *)NULL, (void *)func);
131133

132-
ret = metacallhv_s(handle, "shared_in_s1_and_s2", metacall_null_args, 0);
134+
ret = metacallhv_s(handle2, "shared_in_s1_and_s2", metacall_null_args, 0);
133135

134136
EXPECT_NE((void *)NULL, (void *)ret);
135137

0 commit comments

Comments
 (0)