-
Notifications
You must be signed in to change notification settings - Fork 845
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add channel class and task method for parallel processing in mruby #1336
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for starting your work on the issue.
I am impressed by the fact that you have already succeeded in extending the asynchronous operations that we make. Nice work!
I have left a design comment in-line, please let me know what you think (it's a rough idea and I might be wrong).
lib/handler/mruby/channel.c
Outdated
@@ -0,0 +1,124 @@ | |||
/* | |||
* Copyright (c) 2015-2016 DeNA Co., Ltd., Kazuho Oku |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please change the name to that of yours, and adjust copyright year to the date when you wrote or modified the code (in this case it should be 2017).
I would like to have your name printed on the source code (as well as on the README if your work gets merged).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I appreciate your kindness.
I fixed it here: 60f1d0e
include/h2o/mruby_.h
Outdated
@@ -177,10 +182,18 @@ mrb_value h2o_mruby_http_join_response_callback(h2o_mruby_context_t *ctx, mrb_va | |||
int *next_action); | |||
mrb_value h2o_mruby_http_fetch_chunk_callback(h2o_mruby_context_t *ctx, mrb_value receiver, mrb_value input, | |||
int *next_action); | |||
mrb_value h2o_mruby_channel_shift_callback(h2o_mruby_context_t *ctx, mrb_value receiver, mrb_value input, | |||
int *next_action); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about retaining the queue in mruby side, while restricting use of the C code to when signalling between fibers is necessary?
I believe that doing so would simplify the code and will give us more flexibility in extending the object (for example, it would be easier to add a peek
method).
class Channel
def initialize()
@queue = []
end
def push(o)
@queue << o
self._notify
end
def shift
while true
if !@queue.empty?
return @queue.shift
end
self._wait
end
end
// _notify and _wait are C methods that are called via fiber switching
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree this idea, because it's a little complex to deal with queue in C.
Then I fixed it like below. (I'll add rb file and use script to create embedded code soon.)
064a44b
・For _h2o__channel_wait
, it seems we can't call fiber yield ruby code from C, then I wrote to call _h2o__channel_wait
directly.
・For initializing Channel object, maybe there is better or more simple way, then I'm willing to fix it.
@kazuho Thank you for the comments. I'm really grateful to be involved with such great product. I added task method here (b4b6ede), and it works like below. ・When task with block is called, block is processed firstly. ・In the block, when async function is called, the fiber will be yielded in this method, and pass the resumer and object to context. And application continues running after called running until async function is called in application itself without task. ・When event is called, it's called from mruby_run_fiber as usual and it returns output into mruby_run_fiber. (From second time for calling async function in the block, it doesn't have to call register_receiver because it's called in mruby_run_fiber as usual.) ・When the fiber ends, it returns 0 to mruby_run_fiber method and finish running. Perhaps it can be improved, then please let me know when there is something. I'm willing to fix it. |
4ddb7d3
to
5ef1c7b
Compare
@naritta sorry for being late. I'll review this on Wednesday |
Are there any progress on this change? |
@naritta @tagomoris Sorry for my long long absence! I reviewed and added some inline comments. |
@i110 I can't see your review comments anywhere, Where can I see it? |
include/h2o/mruby_.h
Outdated
/* handler/mruby/channel.c */ | ||
void h2o_mruby_channel_init_context(h2o_mruby_shared_context_t *ctx); | ||
|
||
mrb_value h2o_mruby_channel_shift_callback(h2o_mruby_context_t *ctx, mrb_value receiver, mrb_value input, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
duplicated definition with L185?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I deleted duplicated definition.
792f3f1
lib/handler/mruby/channel.c
Outdated
return mrb_nil_value(); | ||
} | ||
|
||
static mrb_value create_channel_method(mrb_state *mrb, mrb_value self) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about defining normal initialize
method and move these code into that? If so, you can simply call H2O::Channel.new
instead of defining and calling _init
method. Then if you still want handy create_channel
method under Kernel
, you can define it by using H2O::Channel.new
(but IMO it's not so useful)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed to define normal initialize method for initializing channel.
4c17ebd
lib/handler/mruby/channel.c
Outdated
h2o_mruby_run_fiber(ctx->ctx, detach_receiver(ctx), mrb_nil_value(), NULL); | ||
h2o_mruby_shared_context_t *shared_ctx = mrb->ud; | ||
/* When it's called in task, retrieve current_context for next action in task */ | ||
shared_ctx->current_context = ctx->ctx; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you elaborate why this is needed? I haven't understand the purpose for this clearly, but it seems to be something wrong for me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When creating task like this:
task { http_request(req_url).join; ch.push "hello"; http_request(req_url).join; }
channel_notify_method
calls h2o_mruby_run_fiber
, and sets current_context
NULL in this h2o_mruby_run_fiber
.
And after h2o_mruby_run_fiber
, it continues processing task block, but current_context
is NULL, then http_request_method
cannot get current_context
.
I think another way is not setting current_context
NULL if it's call by channel_notify_method
.
If there are other better way, please tell me. I'll fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The most straightforward solution might be doing like this in h2o_mruby_run_fiber
:
h2o_mruby_context_t *old = ctx->shared->current_context;
ctx->shared->current_context = ctx;
/* ... */
ctx->shared->current_context = old;
But in my thoughts, it's better to eliminate nested h2o_mruby_run_fiber call. How about using yield
to switch fibers and use the run loop in h2o_mruby_run_fiber function instead of nested calls?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to use yield
to switch fibers and use the run loop in h2o_mruby_run_fiber, but it says
mruby raised: (eval):5: can't cross C function boundary (FiberError)
It seems impossible to yield from mruby->C->mruby.
If my understanding about this is not correct, please tell me.
Or I'll fix to use straightforward solution above.
if !@queue.empty? | ||
return @queue.shift | ||
end | ||
_h2o__channel_wait(self) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for very trivial point, but I feel that it's clearer and safer to remove while loop.
After the fiber gets resumed, it's guaranteed that @queue
variable is not empty, so how about the following code?
def shift
if @queue.empty?
_h2o__channel_wait(self)
end
raise 'oops' if @queue.empty?
@queue.shift
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed not to use needless loop.
82fa91d
lib/handler/mruby/embedded/core.rb
Outdated
block.call | ||
# For when it's called in h2o_mruby_run_fiber and return output, | ||
# or block doesn't have asynchronous callback | ||
Fiber.yield([0, nil, nil]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about simply returns [0, nil, nil]
instead of yield ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed to simply returns [0, nil, nil]
ea711f5
lib/handler/mruby/embedded/core.rb
Outdated
klass = fiber_res[2][0] | ||
# This should be called only one time. | ||
# After that, the fiber is called in mruby_run_fiber and it register receiver in it. | ||
klass.register_receiver(receiver, klass) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please let me ask some questions around here:
- What does
klass
means? For example, in channel usage, fiber_res[2][0] seems to beH2O::Channel
's instance, not class. - Is it guaranteed that the
klass
object respond_to? :register_receiver ? I mean that many asynchronous functions can be called intask
block, and HTTP response body streaming is one of the examples. So if I understand correctly,http_request(..).join[2].join
fails (but sorry I haven't tried) - When the block yileds (calls defined callback method), there may be some args (i.e. fiber_res[2][1], fiber_res[2][2]..) How to handle that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does klass means? For example, in channel usage, fiber_res[2][0] seems to be H2O::Channel 's instance, not class.
I think we use klass
for instance name in ruby usage. If others is better, I'll fix it.
https://stackoverflow.com/questions/4299289/what-is-the-difference-between-class-and-klass-in-ruby
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it guaranteed that the klass object respond_to? :register_receiver ? I mean that many asynchronous functions can be called in task block, and HTTP response body streaming is one of the examples. So if I understand correctly, http_request(..).join[2].join fails (but sorry I haven't tried)
It's not guaranteed and we must create register_receiver when we create new class having async function. (I forgot to add for HttpInputStream, then I added here.)
aa53e90
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the block yileds (calls defined callback method), there may be some args (i.e. fiber_res[2][1], fiber_res[2][2]..) How to handle that?
sorry, I realized h2o_mruby_http_fetch_chunk_callback
are using args other than self in new code now.
How about this idea?:
- move parts using args to new function named reserved word like
process_args(args)
- If there are some value on args other than self(index 0) in async function, call
process_args(args)
- do same thing for task function calling
process_args(args)
For example, In case of _h2o__http_fetch_chunk
,
- move this(https://github.com/h2o/h2o/blob/master/lib/handler/mruby/http_request.c#L463-L471) from
h2o_mruby_http_fetch_chunk_callback
to new functionprocess_args
, and callprocess_args
- In task function, if there is common same named function
process_args
.
In this way, we don't have to create branch in task function like mruby_run_fiber because of using same named function, but we have to care when we add function using args.
lib/handler/mruby/http_request.c
Outdated
struct st_h2o_mruby_http_request_context_t *ctx; | ||
|
||
mrb_value receiver; | ||
mrb_value self_obj; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it possible to use self
for some reason?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had mistakes, I fixed it to use self.
6316078
@naritta Sorry I forgot to submit reviews. |
Thank you for reviewing, I'll fix it. |
8afb66a
to
82fa91d
Compare
@i110 Thank you for reviewing and sorry to be late, I fixed them. |
@naritta Thank you for working on this. Regarding the current design, I feel that it's けっこうだるい to define How about doing like this? I think this is much simpler than the current implementation, because all of the things required for
for example: mruby.handler: |
puts "# before defining task.."
task {
3.times {|i|
puts "# before http_request (#{i}).."
status, headers, body = http_request('http://example.com/').join
puts "# after http_request (#{i}) (status + #{status})"
}
}
puts "# after defining task, will finish configuration phase!"
proc {|env|
[200, {}, ["hello\n"]]
} outputs the following.
But sorry I had no time to verify my idea and impl, so I would appreciate if you could verify and make it trusty. Of cause before that, please let me know your idea on this 🍣 And please merge the latest master when you get a chance! |
if @queue.empty? | ||
_h2o__channel_wait(self) | ||
end | ||
begin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this begin ~ rescue is not necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I deleted begin ~ rescue
7a05215
lib/handler/mruby/channel.c
Outdated
h2o_mruby_run_fiber(ctx->ctx, detach_receiver(ctx), mrb_nil_value(), NULL); | ||
h2o_mruby_shared_context_t *shared_ctx = mrb->ud; | ||
/* When it's called in task, retrieve current_context for next action in task */ | ||
shared_ctx->current_context = ctx->ctx; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The most straightforward solution might be doing like this in h2o_mruby_run_fiber
:
h2o_mruby_context_t *old = ctx->shared->current_context;
ctx->shared->current_context = ctx;
/* ... */
ctx->shared->current_context = old;
But in my thoughts, it's better to eliminate nested h2o_mruby_run_fiber call. How about using yield
to switch fibers and use the run loop in h2o_mruby_run_fiber function instead of nested calls?
h2o_mruby_shared_context_t *shared_ctx = mrb->ud; | ||
|
||
struct st_h2o_mruby_channel_context_t *ctx; | ||
ctx = h2o_mem_alloc(sizeof(*ctx)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to leak. You have to free this in on_gc_dispose_channel
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed to free ctx and check null of values of that.
05790cd
include/h2o/mruby_.h
Outdated
@@ -121,6 +125,7 @@ typedef struct st_h2o_mruby_generator_t { | |||
#define H2O_MRUBY_CALLBACK_ID_SEND_CHUNKED_EOS -4 | |||
#define H2O_MRUBY_CALLBACK_ID_HTTP_JOIN_RESPONSE -5 | |||
#define H2O_MRUBY_CALLBACK_ID_HTTP_FETCH_CHUNK -6 | |||
#define H2O_MRUBY_CALLBACK_ID_CHANNEL_SHIFT -7 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
H2O_MRUBY_CALLBACK_ID_CHANNEL_WAIT
might be better name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed to use name H2O_MRUBY_CALLBACK_ID_CHANNEL_WAIT
36f718e
lib/handler/mruby/channel.c
Outdated
static mrb_value channel_notify_method(mrb_state *mrb, mrb_value self) | ||
{ | ||
struct st_h2o_mruby_channel_context_t *ctx; | ||
ctx = DATA_PTR(self); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's better to use mrb_data_check_get_ptr
instead of DATA_PTR
macro, or at least be consistent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed to use mrb_data_check_get_ptr
69a4baf
t/50mruby-channel.t
Outdated
is $stdout, 1; | ||
}; | ||
|
||
plan skip_all => 'mruby support is off' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JFYI, you don't have to call skip_all
multiple times
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I deleted needless skip_all
8f4c9bf
t/50mruby-channel.t
Outdated
/: | ||
mruby.handler: | | ||
Proc.new do |env| | ||
ch = create_channel |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
H2O::Channel.new?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fix to use new for creating instances.
7edafbc
t/50mruby-task.t
Outdated
is $stdout, "123456"; | ||
}; | ||
|
||
done_testing(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would appreciate if you could add the tests which joins response body :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a test for that.
250acdd
fd273ee
to
df62ee1
Compare
…p response processing
@naritta @tagomoris Sorry for my belated response.. I filed naritta#1 to your forked repo, which merges the latest master and contains some fixes. If it's merged, the changes will appear here :D |
Parallel http join
@i110 Thank you for reviewing and fixing. I could make sure it works well. |
lib/handler/mruby.c
Outdated
|
||
mrb_gc_protect(mrb, receiver); | ||
mrb_gc_protect(mrb, input); | ||
} | ||
|
||
if (status == 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I forgot to remove this check and goto. I introduced _h2o__finish_child_fiber, so this is no longer needed. Could you remove this?
From my viewpoint this PR seems to be ready to merged. @kazuho Any thoughts? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am fascinated by how cleanly this big new feature is implemented. Thank you for working on it. I believe that the code is very near to getting merged.
I have left my comments in-line. Please let me know what you think.
lib/handler/mruby/embedded.c.h
Outdated
" def task(&block)\n" \ | ||
" fiber = Fiber.new do\n" \ | ||
" block.call\n" \ | ||
" _h2o__finish_child_fiber()\n" \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you mind elaborating what happens if block.call
raises an exception? My expectation is that h2o__finish_child_fiber()
will not be called in such case.
If calling h2o__finish_child_fiber()
makes any difference, then I believe that we should call the function even if block.call
raises an error. Or if h2o__finish_child_fiber()
is a noop, can we eliminate the function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now, entire application will stop when block.call
raises.
Then I fixed to call _h2o__send_error
and not to call _h2o__finish_child_fiber
intentionally.
52ea223
By this, task will raise an error and only task dies but parent application will not stop when fiber in task raises.
If this design is wrong and I should make it parent application stop when task raises, I'll fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perfect! :D
lib/handler/mruby/channel.c
Outdated
|
||
static void attach_receiver(struct st_h2o_mruby_channel_context_t *ctx, mrb_value receiver) | ||
{ | ||
assert(mrb_nil_p(ctx->receiver)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please elaborate how we ensure that a Channel will have at most one listeners?
I couldn't find code that provides such guarantee, and wonder what happens if two fibers call shift
of one channel object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PS. Please note that I am not suggesting that we should support multiple readers. Supporting only one reader is fine, but an error in mruby script should be reported as an mruby exception; not an abrupt termination of the server process.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed to raise error when shift is called though it's already registered.
2cf40c2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@naritta Would you mind supporting multiple listener (shifter)? Discussed with @kazuho today, it may be useful in minor cases and can be easily implemented .
To implement that, simply do:
- change receiver to receivers (Array)
- use mrb_ary_push instead of attach_receiver
- use mrb_ary_shift instead of detach_receiver
How do you feel?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds cool. I fixed to support multiple listener like above.
916cab1
lib/handler/mruby/channel.c
Outdated
{ | ||
struct st_h2o_mruby_channel_context_t *ctx = _ctx; | ||
assert(ctx != NULL); /* ctx can only be disposed by gc, so data binding has been never removed */ | ||
free(ctx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to call mrb_gc_unregister(mrb, ctx->receiver)
?
I believe that the question boils down to if there is a chance in GC collecting the channel object while a receiver is being attached to a object; and to me, something like below seems to trigger such condition:
task {
H2O::Channel.new.shift
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed to call mrb_gc_unregister.
da33b13
10e5ed5
to
52ea223
Compare
@kazuho Thank you for reviewing. I fixed them and I commented. Could you check it? |
lib/handler/mruby/channel.c
Outdated
{ | ||
struct st_h2o_mruby_channel_context_t *ctx = _ctx; | ||
assert(ctx != NULL); /* ctx can only be disposed by gc, so data binding has been never removed */ | ||
mrb_gc_unregister(mrb, ctx->receiver); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a check that ensures ctx->receiver is not nil? i.e. if (!mrb_nil_p(ctx->receiver))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed to check if ctx->receiver
is not nil before mrb_gc_unregister
.
4312b53
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At this time we definitely set receivers
in initialization, so this nil check you newly added is no longer needed. Sorry for the confusion 😵
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I forgot to check it. I deleted it.
03c0a42
77dec08
to
52ea223
Compare
a2ad598
to
916cab1
Compare
@i110 Thank you for reviewing. I fixed to support multiple listener and could you check it? |
lib/handler/mruby/channel.c
Outdated
@@ -73,7 +56,7 @@ static mrb_value channel_initialize_method(mrb_state *mrb, mrb_value self) | |||
memset(ctx, 0, sizeof(*ctx)); | |||
assert(shared_ctx->current_context != NULL); | |||
ctx->ctx = shared_ctx->current_context; | |||
ctx->receiver = mrb_nil_value(); | |||
ctx->receivers = mrb_ary_new(mrb); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
receivers
should be mrb_gc_register
ed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I see. Do you think it should be mrb_gc_register
or mrb_gc_protect
after shited also?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I don't understand your question. mrb_gc_registerとmrb_gc_protectのどちらを使うべきかという意味ですか?であれば、ここではregisterのほうですね。 (protectだとgc arena indexがrestoreされたらgcされてしまうので)
それともshiftされたobjectも保護すべきかどうか、という質問ですかね? (shited => shifted?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for confusing.
shiftされたobjectも保護すべきかどうかという質問です。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it enough becausemrb_gc_arena_save
and mrb_gc_arena_restore
is done here?
https://github.com/naritta/h2o/blob/916cab15f8f88cfb608b769379f6af4139fb8612/lib/handler/mruby/channel.c#L74-L77
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I think you have to call mrb_gc_protect(mrb, shifted_receiver)
immediately after shifting from receiver array. Otherwise it can be GCed in mrb_funcall function before call
method of that Proc is called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I see. I fixed to call mrb_gc_protect
here.
8926f7d
Thank you so much for your effort! |
Thank you for review and great opportunity! |
This PR is for #1329
TODO: