Skip to content

Commit 98a2d1d

Browse files
committed
mark julia threads as initialized
ensures that cfunction can see that Julia state is initialized on this thread also upgrades the embedding/examples test to handle exceptions better (e.g. to actually detect them) while testing for correctness
1 parent 1b560bd commit 98a2d1d

File tree

3 files changed

+78
-21
lines changed

3 files changed

+78
-21
lines changed

examples/embedding/embedding-test.jl

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,19 @@
44
using Base.Test
55

66
@test length(ARGS) == 1
7-
let
7+
@testset "embedding example" begin
88
stdout = Pipe()
99
stderr = Pipe()
1010
p = spawn(pipeline(Cmd(ARGS), stdin=DevNull, stdout=stdout, stderr=stderr))
1111
close(stdout.in)
1212
close(stderr.in)
13-
stderr_task = @async readlines(stderr)
14-
lines = readlines(stdout)
15-
@test length(lines) == 6
16-
@test parse(Float64, lines[1]) sqrt(2)
17-
lines = wait(stderr_task)
18-
@test lines == ["UndefVarError(:this_function_does_not_exist)"]
13+
stdout_task = @async readlines(stdout)
14+
stderr = read(stderr, String)
15+
@test stderr == "MethodError: no method matching this_function_has_no_methods()\n"
1916
@test success(p)
17+
lines = wait(stdout_task)
18+
@test length(lines) == 9
19+
@test parse(Float64, lines[1]) sqrt(2)
20+
@test lines[8] == "called bar"
21+
@test lines[9] == "calling new bar"
2022
end

examples/embedding/embedding.c

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,39 @@ double my_c_sqrt(double x)
1414
return sqrt(x);
1515
}
1616

17+
jl_value_t *checked_eval_string(const char* code)
18+
{
19+
jl_value_t *result = jl_eval_string(code);
20+
if (jl_exception_occurred()) {
21+
// none of these allocate, so a gc-root (JL_GC_PUSH) is not necessary
22+
jl_call2(jl_get_function(jl_base_module, "showerror"),
23+
jl_stderr_obj(),
24+
jl_exception_occurred());
25+
jl_printf(jl_stderr_stream(), "\n");
26+
jl_atexit_hook(1);
27+
exit(1);
28+
}
29+
assert(result && "Missing return value but no exception occurred!");
30+
return result;
31+
}
32+
1733
int main()
1834
{
1935
jl_init();
2036

2137
{
22-
// Simple running Julia code
38+
// Simple running of Julia code
2339

24-
jl_eval_string("println(sqrt(2.0))");
40+
checked_eval_string("println(sqrt(2.0))");
2541
}
2642

2743
{
2844
// Accessing the return value
2945

30-
jl_value_t *ret = jl_eval_string("sqrt(2.0)");
46+
jl_value_t *ret = checked_eval_string("sqrt(2.0)");
3147
double retDouble = jl_unbox_float64(ret);
3248
printf("sqrt(2.0) in C: %e\n", retDouble);
49+
fflush(stdout);
3350
}
3451

3552
{
@@ -40,62 +57,98 @@ int main()
4057
jl_value_t* ret = jl_call1(func, argument);
4158
double retDouble = jl_unbox_float64(ret);
4259
printf("sqrt(2.0) in C: %e\n", retDouble);
60+
fflush(stdout);
4361
}
4462

4563
{
4664
// 1D arrays
4765

48-
jl_value_t* array_type = jl_apply_array_type( (jl_value_t*)jl_float64_type, 1 );
49-
jl_array_t* x = jl_alloc_array_1d(array_type , 10);
66+
jl_value_t* array_type = jl_apply_array_type((jl_value_t*)jl_float64_type, 1);
67+
jl_array_t* x = jl_alloc_array_1d(array_type, 10);
68+
// JL_GC_PUSH* is required here to ensure that `x` is not deleted before
69+
// (aka, is gc-rooted until) the program reaches the corresponding JL_GC_POP()
5070
JL_GC_PUSH1(&x);
5171

5272
double* xData = jl_array_data(x);
5373

5474
size_t i;
55-
for(i=0; i<jl_array_len(x); i++)
75+
for (i = 0; i < jl_array_len(x); i++)
5676
xData[i] = i;
5777

5878
jl_function_t *func = jl_get_function(jl_base_module, "reverse!");
5979
jl_call1(func, (jl_value_t*) x);
6080

6181
printf("x = [");
62-
for(i=0; i<jl_array_len(x); i++)
82+
for (i = 0; i < jl_array_len(x); i++)
6383
printf("%e ", xData[i]);
6484
printf("]\n");
85+
fflush(stdout);
6586

6687
JL_GC_POP();
6788
}
6889

6990
{
70-
// define julia function and call it
91+
// Defining a Julia function and calling it
7192

72-
jl_eval_string("my_func(x) = 2*x");
93+
checked_eval_string("my_func(x) = 2 * x");
7394

7495
jl_function_t *func = jl_get_function(jl_current_module, "my_func");
7596
jl_value_t* arg = jl_box_float64(5.0);
7697
double ret = jl_unbox_float64(jl_call1(func, arg));
7798

7899
printf("my_func(5.0) = %f\n", ret);
100+
fflush(stdout);
79101
}
80102

81103
{
82-
// call c function
104+
// Calling a C function from Julia (from C)
83105

84-
jl_eval_string("println( ccall( :my_c_sqrt, Float64, (Float64,), 2.0 ) )");
106+
// in a shared library (exported, by name)
107+
checked_eval_string("println( ccall(:my_c_sqrt, Float64, (Float64,), 2.0) )");
108+
109+
// or via a pointer
110+
jl_value_t *call_by_ptr = checked_eval_string(
111+
"my_c_sqrt -> println( ccall(my_c_sqrt, Float64, (Float64,), 2.0) )");
112+
jl_call1(call_by_ptr, jl_box_voidpointer(my_c_sqrt));
85113
}
86114

87115
{
88-
// check for exceptions
116+
// Handling exceptions gracefully
89117

90-
jl_eval_string("this_function_does_not_exist()");
118+
jl_value_t *f = checked_eval_string("function this_function_has_no_methods end");
119+
jl_call0(f);
91120

92121
if (jl_exception_occurred()) {
93-
jl_call2(jl_get_function(jl_base_module, "show"), jl_stderr_obj(), jl_exception_occurred());
122+
jl_call2(jl_get_function(jl_base_module, "showerror"),
123+
jl_stderr_obj(),
124+
jl_exception_occurred());
94125
jl_printf(jl_stderr_stream(), "\n");
95126
}
96127

97128
}
98129

130+
{
131+
// Creating and using a native C function handle
132+
// to a Julia function signature
133+
134+
checked_eval_string(
135+
"function bar()\n"
136+
" println(\"called bar\")\n"
137+
" random_return_value = 42\n"
138+
"end");
139+
checked_eval_string(
140+
"function bar_from_c()\n"
141+
" bar()\n"
142+
" nothing\n"
143+
"end");
144+
typedef void (*Func_VOID__VOID)(void);
145+
jl_value_t *pbar = jl_eval_string("cfunction(bar_from_c, Void, ())");
146+
Func_VOID__VOID bar = (Func_VOID__VOID)jl_unbox_voidpointer(pbar);
147+
bar();
148+
checked_eval_string("bar() = println(\"calling new bar\")");
149+
bar();
150+
}
151+
99152
int ret = 0;
100153
jl_atexit_hook(ret);
101154
return ret;

src/threading.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,8 @@ static void ti_initthread(int16_t tid)
258258
#ifndef _OS_WINDOWS_
259259
ptls->system_id = pthread_self();
260260
#endif
261+
assert(ptls->world_age == 0);
262+
ptls->world_age = 1; // OK to run Julia code on this thread
261263
ptls->tid = tid;
262264
ptls->pgcstack = NULL;
263265
ptls->gc_state = 0; // GC unsafe

0 commit comments

Comments
 (0)