Skip to content

Commit 9524ae1

Browse files
committedMar 19, 2016
Reworked starting and operating on Threads.
1 parent bcd14db commit 9524ae1

File tree

5 files changed

+154
-330
lines changed

5 files changed

+154
-330
lines changed
 

‎core/thread.rb

+41-150
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,54 @@
66
class Thread
77
attr_reader :recursive_objects
88
attr_reader :pid
9+
attr_reader :exception
910

10-
def self.start(*args)
11-
raise ArgumentError.new("no block passed to Thread.start") unless block_given?
11+
def self.new(*args, &block)
12+
thr = Rubinius.invoke_primitive :thread_s_new, args, block, self
1213

13-
thr = Rubinius.invoke_primitive :thread_allocate, self
14-
15-
Rubinius.asm(args, thr) do |args, obj|
16-
run obj
17-
dup
14+
Rubinius::VariableScope.of_sender.locked!
1815

19-
run args
20-
push_block
21-
send_with_splat :__thread_initialize__, 0, true
22-
# no pop here, as .asm blocks imply a pop as they're not
23-
# allowed to leak a stack value
16+
unless thr.send :initialized?
17+
raise ThreadError, "Thread#initialize not called"
2418
end
2519

2620
return thr
2721
end
2822

23+
def self.start(*args, &block)
24+
raise ArgumentError.new("no block passed to Thread.start") unless block
25+
26+
Rubinius.invoke_primitive :thread_s_start, args, block, self
27+
end
28+
2929
class << self
3030
alias_method :fork, :start
3131
end
3232

33+
def initialize(*args, &block)
34+
unless block
35+
Kernel.raise ThreadError, "no block passed to Thread#initialize"
36+
end
37+
38+
if @initialized
39+
Kernel.raise ThreadError, "already initialized thread"
40+
end
41+
42+
@args = args
43+
@block = block
44+
@initialized = true
45+
46+
Thread.current.group.add self
47+
end
48+
49+
alias_method :__thread_initialize__, :initialize
50+
51+
def initialized?
52+
@initialized
53+
end
54+
55+
private :initialized?
56+
3357
def self.current
3458
Rubinius.primitive :thread_current
3559
Kernel.raise PrimitiveFailure, "Thread.current primitive failed"
@@ -54,21 +78,6 @@ def self.stop
5478
nil
5579
end
5680

57-
def fork
58-
Rubinius.primitive :thread_fork
59-
Kernel.raise ThreadError, "Thread#fork failed, thread already started or dead"
60-
end
61-
62-
def raise_prim(exc)
63-
Rubinius.primitive :thread_raise
64-
Kernel.raise PrimitiveFailure, "Thread#raise primitive failed"
65-
end
66-
67-
def kill_prim
68-
Rubinius.primitive :thread_kill
69-
Kernel.raise PrimitiveFailure, "Thread#kill primitive failed"
70-
end
71-
7281
def wakeup
7382
Rubinius.primitive :thread_wakeup
7483
Kernel.raise ThreadError, "Thread#wakeup primitive failed, thread may be dead"
@@ -95,21 +104,6 @@ def mri_backtrace
95104
Kernel.raise PrimitiveFailure, "Thread#mri_backtrace primitive failed"
96105
end
97106

98-
def unlock_locks
99-
Rubinius.primitive :thread_unlock_locks
100-
Kernel.raise PrimitiveFailure, "Thread#unlock_locks primitive failed"
101-
end
102-
103-
def current_exception
104-
Rubinius.primitive :thread_current_exception
105-
Kernel.raise PrimitiveFailure, "Thread#current_exception primitive failed"
106-
end
107-
108-
def set_exception(exception)
109-
Rubinius.primitive :thread_set_exception
110-
Kernel.raise PrimitiveFailure, "Thread#set_exception primitive failed"
111-
end
112-
113107
@abort_on_exception = false
114108

115109
def self.abort_on_exception
@@ -138,50 +132,6 @@ def inspect
138132

139133
alias_method :to_s, :inspect
140134

141-
def self.new(*args)
142-
thr = Rubinius.invoke_primitive :thread_allocate, self
143-
144-
Rubinius::VariableScope.of_sender.locked!
145-
146-
Rubinius.asm(args, thr) do |args, obj|
147-
run obj
148-
dup
149-
150-
run args
151-
push_block
152-
send_with_splat :initialize, 0, true
153-
# no pop here, as .asm blocks imply a pop as they're not
154-
# allowed to leak a stack value
155-
end
156-
157-
unless thr.thread_is_setup?
158-
raise ThreadError, "Thread#initialize not called"
159-
end
160-
161-
return thr
162-
end
163-
164-
def initialize(*args, &block)
165-
unless block
166-
Kernel.raise ThreadError, "no block passed to Thread#initialize"
167-
end
168-
169-
@args = args
170-
@block = block
171-
172-
th_group = Thread.current.group
173-
174-
th_group.add self
175-
176-
fork
177-
end
178-
179-
alias_method :__thread_initialize__, :initialize
180-
181-
def thread_is_setup?
182-
@block != nil
183-
end
184-
185135
def alive?
186136
Rubinius.synchronize(self) do
187137
@alive
@@ -233,14 +183,9 @@ def group
233183
end
234184

235185
def raise(exc=undefined, msg=nil, trace=nil)
236-
Rubinius.lock(self)
237-
238-
unless @alive
239-
Rubinius.unlock(self)
240-
return self
241-
end
186+
Rubinius.synchronize(self) do
187+
return self unless @alive
242188

243-
begin
244189
if undefined.equal? exc
245190
no_argument = true
246191
exc = active_exception
@@ -265,13 +210,10 @@ def raise(exc=undefined, msg=nil, trace=nil)
265210
if self == Thread.current
266211
Kernel.raise exc
267212
else
268-
raise_prim exc
213+
Rubinius.invoke_primitive :thread_raise, self, exc
269214
end
270-
ensure
271-
Rubinius.unlock(self)
272215
end
273216
end
274-
private :raise_prim
275217

276218
def [](key)
277219
locals_aref(Rubinius::Type.coerce_to_symbol(key))
@@ -355,61 +297,10 @@ def self.kill(thread)
355297

356298
alias_method :run, :wakeup
357299

358-
# Called by Thread#fork in the new thread
359-
#
360-
def __run__
361-
begin
362-
begin
363-
Rubinius.unlock(self)
364-
@result = @block.call(*@args)
365-
ensure
366-
begin
367-
# We must lock self in a careful way.
368-
#
369-
# At this point, it's possible that an other thread does Thread#raise
370-
# and then our execution is interrupted AT ANY GIVEN TIME. We
371-
# absolutely must make sure to lock self as soon as possible to lock
372-
# out interrupts from other threads.
373-
#
374-
# Rubinius.uninterrupted_lock(self) just does that.
375-
#
376-
# Notice that this can't be moved to other methods and there should be
377-
# no preceding code before it in the enclosing ensure clause.
378-
# These are to prevent any interrupted lock failures.
379-
Rubinius.uninterrupted_lock(self)
380-
381-
# Now, we locked self. No other thread can interrupt this thread
382-
# anymore.
383-
# If there is any not-triggered interrupt, check and process it. In
384-
# either case, we jump to the following ensure clause.
385-
Rubinius.check_interrupts
386-
ensure
387-
unlock_locks
388-
end
389-
end
390-
rescue Exception => e
391-
set_exception e
392-
393-
STDERR.puts "Exception in thread: #{e.message} (#{e.class})" if $DEBUG
394-
395-
if abort_on_exception or Thread.abort_on_exception
396-
Thread.main.raise e
397-
end
398-
ensure
399-
Rubinius::Mirror.reflect(@group).remove self
400-
401-
if Rubinius.thread_state[0] == :thread_kill
402-
@killed = true
403-
end
404-
405-
Rubinius.unlock(self)
406-
end
407-
end
408-
409300
def kill
410301
@sleep = false
411302
Rubinius.synchronize(self) do
412-
kill_prim
303+
Rubinius.invoke_primitive :thread_kill, self
413304
end
414305
self
415306
end
@@ -419,7 +310,7 @@ def kill
419310

420311
def value
421312
join
422-
@killed ? nil : @result
313+
@value
423314
end
424315

425316
def active_exception

‎core/thread_mirror.rb

+14
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,20 @@ class Thread < Mirror
44
def group=(group)
55
Rubinius.invoke_primitive :object_set_ivar, @object, :@group, group
66
end
7+
8+
def finish
9+
Rubinius::Mirror.reflect(@object.group).remove @object
10+
11+
if exception = @object.exception
12+
if $DEBUG
13+
STDERR.puts "Exception in thread: #{exception.message} (#{exception.class})"
14+
end
15+
16+
if @object.abort_on_exception or Thread.abort_on_exception
17+
Thread.main.raise exception
18+
end
19+
end
20+
end
721
end
822
end
923
end

‎machine/builtin/thread.cpp

+65-82
Original file line numberDiff line numberDiff line change
@@ -110,42 +110,73 @@ namespace rubinius {
110110
}
111111
}
112112

113-
Object* send_run(STATE) {
114-
return state->vm()->thread.get()->send(state, state->symbol("__run__"));
113+
Object* run_instance(STATE) {
114+
// These are all referenced, so OnStack is not necessary.
115+
Thread* thread = state->vm()->thread.get();
116+
Array* args = thread->args();
117+
Object* block = thread->block();
118+
119+
if(thread->initialized()->false_p() || args->nil_p() || block->nil_p()) {
120+
return cNil;
121+
}
122+
123+
Object* value = block->send(state, G(sym_call), args, block);
124+
125+
thread->exception(state, state->vm()->thread_state()->current_exception());
126+
127+
if(state->vm()->thread_state()->raise_reason() == cThreadKill) {
128+
thread->value(state, cNil);
129+
} else if(value) {
130+
thread->value(state, value);
131+
}
132+
133+
Object* mirror = G(mirror)->send(state, state->symbol("reflect"),
134+
Array::from_tuple(state, Tuple::from(state, 1, thread)));
135+
mirror->send(state, state->symbol("finish"));
136+
137+
return value;
115138
}
116139

117-
Thread* Thread::allocate(STATE, Object* self) {
118-
Thread* thread = Thread::create(state, self, send_run);
140+
Thread* Thread::s_new(STATE, Object* self, Array* args, Object* block) {
141+
Thread* thread = Thread::create(state, self, run_instance);
119142

120143
CallFrame* call_frame = state->vm()->get_ruby_frame(1);
121144

122-
utilities::logger::write("create thread: %s, %s:%d",
145+
utilities::logger::write("new thread: %s, %s:%d",
123146
thread->vm()->name().c_str(),
124147
call_frame->file(state)->cpp_str(state).c_str(),
125148
call_frame->line(state));
126149

150+
if(!thread->send(state, state->symbol("initialize"), args, block, true)) {
151+
return NULL;
152+
}
153+
154+
thread->fork(state);
155+
127156
return thread;
128157
}
129158

130-
Thread* Thread::current(STATE) {
131-
return state->vm()->thread.get();
132-
}
159+
Thread* Thread::s_start(STATE, Object* self, Array* args, Object* block) {
160+
Thread* thread = Thread::create(state, self, run_instance);
133161

134-
Object* Thread::unlock_locks(STATE) {
135-
Thread* self = this;
136-
OnStack<1> os(state, self);
162+
CallFrame* call_frame = state->vm()->get_ruby_frame(1);
137163

138-
memory::LockedObjects& los = self->vm_->locked_objects();
139-
for(memory::LockedObjects::iterator i = los.begin();
140-
i != los.end();
141-
++i) {
142-
ObjectHeader* locked = *i;
143-
if(locked != self) {
144-
locked->unlock_for_terminate(state);
145-
}
164+
utilities::logger::write("start thread: %s, %s:%d",
165+
thread->vm()->name().c_str(),
166+
call_frame->file(state)->cpp_str(state).c_str(),
167+
call_frame->line(state));
168+
169+
if(!thread->send(state, state->symbol("__thread_initialize__"), args, block, true)) {
170+
return NULL;
146171
}
147-
los.clear();
148-
return cNil;
172+
173+
thread->fork(state);
174+
175+
return thread;
176+
}
177+
178+
Thread* Thread::current(STATE) {
179+
return state->vm()->thread.get();
149180
}
150181

151182
void Thread::unlock_after_fork(STATE) {
@@ -255,40 +286,20 @@ namespace rubinius {
255286
Thread* self = this;
256287
OnStack<1> os(state, self);
257288

258-
self->init_lock_.lock();
259-
260289
pthread_attr_t attrs;
261290
pthread_attr_init(&attrs);
262291
pthread_attr_setstacksize(&attrs, THREAD_STACK_SIZE);
263292
pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
264293

265-
int error;
266-
267-
error = pthread_create(&self->vm_->os_thread(), &attrs,
294+
int status = pthread_create(&self->vm_->os_thread(), &attrs,
268295
function, (void*)self->vm_);
269296

270297
pthread_attr_destroy(&attrs);
271298

272-
if(error) {
273-
return error;
274-
} else {
275-
// We can't return from here until the new thread completes a minimal
276-
// initialization. After the initialization, it unlocks init_lock_.
277-
// So, wait here until we can lock init_lock_ after that.
278-
self->init_lock_.lock();
279-
280-
// We locked init_lock_. And we are sure that the new thread completed
281-
// the initialization.
282-
// Locking init_lock_ isn't needed anymore, so unlock it.
283-
self->init_lock_.unlock();
284-
285-
return 0;
286-
}
299+
return status;
287300
}
288301

289302
Object* Thread::main_thread(STATE) {
290-
state->vm()->thread->hard_unlock(state);
291-
292303
std::string& runtime = state->shared().env()->runtime_path();
293304

294305
G(rubinius)->set_const(state, "Signature",
@@ -301,7 +312,6 @@ namespace rubinius {
301312

302313
state->shared().env()->load_core(state, runtime);
303314

304-
state->vm()->thread->alive(state, cTrue);
305315
state->vm()->thread_state()->clear();
306316

307317
state->shared().start_console(state);
@@ -325,11 +335,11 @@ namespace rubinius {
325335
// Enable the JIT after the core library has loaded
326336
G(jit)->enable(state);
327337

328-
Object* exit = instance->send(state, state->symbol("main"));
338+
Object* value = instance->send(state, state->symbol("main"));
329339

330340
state->shared().signals()->system_exit(state->vm()->thread_state()->raise_value());
331341

332-
return exit;
342+
return value;
333343
}
334344

335345
void* Thread::run(void* ptr) {
@@ -353,30 +363,23 @@ namespace rubinius {
353363

354364
NativeMethod::init_thread(state);
355365

356-
// Lock the thread object and unlock it at __run__ in the ruby land.
357-
vm->thread->alive(state, cTrue);
358-
vm->thread->init_lock_.unlock();
359-
360-
// TODO: remove use of init_lock
361-
// Become GC-dependent after unlocking init_lock_ to avoid deadlocks.
362-
// gc_dependent may lock when it detects GC is happening. Also the parent
363-
// thread is locked until init_lock_ is unlocked by this child thread.
364366
state->vm()->become_managed();
365-
vm->thread->hard_lock(state, 0);
366367

367368
vm->shared.tool_broker()->thread_start(state);
368-
Object* ret = vm->thread->function_(state);
369+
Object* value = vm->thread->function_(state);
369370
vm->shared.tool_broker()->thread_stop(state);
370371

371372
vm->thread->join_lock_.lock();
372373
vm->thread->stopped();
373374

374-
memory::LockedObjects& los = state->vm()->locked_objects();
375-
for(memory::LockedObjects::iterator i = los.begin();
376-
i != los.end();
377-
++i) {
375+
memory::LockedObjects& locked_objects = state->vm()->locked_objects();
376+
for(memory::LockedObjects::iterator i = locked_objects.begin();
377+
i != locked_objects.end();
378+
++i)
379+
{
378380
(*i)->unlock_for_terminate(state);
379381
}
382+
locked_objects.clear();
380383

381384
vm->thread->join_cond_.broadcast();
382385
vm->thread->join_lock_.unlock();
@@ -387,7 +390,7 @@ namespace rubinius {
387390

388391
vm->become_unmanaged();
389392

390-
if(vm->main_thread_p() || (!ret && vm->thread_state()->raise_reason() == cExit)) {
393+
if(vm->main_thread_p() || (!value && vm->thread_state()->raise_reason() == cExit)) {
391394
state->shared().signals()->system_exit(vm->thread_state()->raise_value());
392395
}
393396

@@ -399,19 +402,12 @@ namespace rubinius {
399402
return 0;
400403
}
401404

402-
Object* Thread::fork(STATE) {
403-
// If the thread is already alive or already ran, we can't use it anymore.
404-
if(CBOOL(alive()) || !vm_ || vm_->zombie_p()) {
405-
return Primitives::failure();
406-
}
407-
405+
void Thread::fork(STATE) {
408406
if(int error = start_thread(state, Thread::run)) {
409407
char buf[RBX_STRERROR_BUFSIZE];
410408
char* err = RBX_STRERROR(error, buf, RBX_STRERROR_BUFSIZE);
411409
Exception::raise_thread_error(state, err);
412410
}
413-
414-
return cNil;
415411
}
416412

417413
Object* Thread::pass(STATE) {
@@ -443,19 +439,6 @@ namespace rubinius {
443439
return exc;
444440
}
445441

446-
Object* Thread::set_exception(STATE, Exception* exc) {
447-
exception(state, exc);
448-
return exc;
449-
}
450-
451-
Object* Thread::current_exception(STATE) {
452-
utilities::thread::SpinLock::LockGuard guard(init_lock_);
453-
454-
if(!vm_) return cNil;
455-
456-
return vm_->thread_state()->current_exception();
457-
}
458-
459442
Object* Thread::kill(STATE) {
460443
utilities::thread::SpinLock::LockGuard guard(init_lock_);
461444

‎machine/builtin/thread.hpp

+20-61
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ namespace rubinius {
2121
* Thread execution.
2222
*/
2323
class Thread : public Object {
24+
Array* args_; // slot
25+
Object* block_; // slot
2426
Object* alive_; // slot
2527
Object* sleep_; // slot
2628
Channel* control_channel_; // slot
@@ -30,12 +32,12 @@ namespace rubinius {
3032
Randomizer* randomizer_; // slot
3133
LookupTable* locals_; // slot
3234
Object* group_; // slot
33-
Object* result_; // slot
35+
Object* value_; // slot
3436
Exception* exception_; // slot
3537
Object* critical_; // slot
36-
Object* killed_; // slot
3738
Fixnum* priority_; // slot
3839
Fixnum* pid_; // slot
40+
Object* initialized_; // slot
3941

4042
utilities::thread::SpinLock init_lock_;
4143
utilities::thread::Mutex join_lock_;
@@ -53,28 +55,32 @@ namespace rubinius {
5355

5456
static void bootstrap(STATE);
5557
static void initialize(STATE, Thread* obj) {
56-
obj->alive_ = nil<Object>();
58+
obj->args_ = nil<Array>();
59+
obj->block_ = cNil;
60+
obj->alive_ = cTrue;
5761
obj->sleep_ = cFalse;
5862
obj->control_channel_ = nil<Channel>();
5963
obj->recursive_objects(state, LookupTable::create(state));
6064
obj->debugger_thread_ = nil<Thread>();
6165
obj->thread_id_ = nil<Fixnum>();
6266
obj->randomizer_ = nil<Randomizer>();
6367
obj->locals(state, LookupTable::create(state));
64-
obj->group_ = nil<Object>();
65-
obj->result_ = cFalse;
68+
obj->group_ = cNil;
69+
obj->value_ = cNil;
6670
obj->exception_ = nil<Exception>();
6771
obj->critical_ = cFalse;
68-
obj->killed_ = cFalse;
6972
obj->priority_ = Fixnum::from(0);
7073
obj->pid_ = Fixnum::from(0);
74+
obj->initialized_ = cFalse;
7175
obj->init_lock_.init();
7276
obj->join_lock_.init();
7377
obj->join_cond_.init();
7478
obj->vm_ = 0;
7579
}
7680

7781
public:
82+
attr_accessor(args, Array);
83+
attr_accessor(block, Object);
7884
attr_accessor(alive, Object);
7985
attr_accessor(sleep, Object);
8086
attr_accessor(control_channel, Channel);
@@ -84,39 +90,24 @@ namespace rubinius {
8490
attr_accessor(randomizer, Randomizer);
8591
attr_accessor(locals, LookupTable);
8692
attr_accessor(group, Object);
87-
attr_accessor(result, Object);
93+
attr_accessor(value, Object);
8894
attr_accessor(exception, Exception);
8995
attr_accessor(critical, Object);
90-
attr_accessor(killed, Object);
9196
attr_accessor(priority, Fixnum);
9297
attr_accessor(pid, Fixnum);
98+
attr_accessor(initialized, Object);
9399

94100
VM* vm() const {
95101
return vm_;
96102
}
97103

98104
public:
99105

100-
/**
101-
* Allocate a Thread object.
102-
*
103-
* Object is in a valid but not running state.
104-
* It still assumes that #initialize will be
105-
* called to fully set it up. The object is
106-
* not yet associated with an actual native
107-
* thread.
108-
*
109-
* This method also creates a new VM object
110-
* to represent its state.
111-
*
112-
* @see Thread::fork()
113-
* @see Thread::create()
114-
*
115-
* @see machine/vm.hpp
116-
* @see kernel/thread.rb
117-
*/
118-
// Rubinius.primitive :thread_allocate
119-
static Thread* allocate(STATE, Object* self);
106+
// Rubinius.primitive :thread_s_new
107+
static Thread* s_new(STATE, Object* self, Array* args, Object* block);
108+
109+
// Rubinius.primitive :thread_s_start
110+
static Thread* s_start(STATE, Object* self, Array* args, Object* block);
120111

121112
/**
122113
* Returns the Thread object for the state.
@@ -140,27 +131,7 @@ namespace rubinius {
140131

141132
public: /* Instance primitives */
142133

143-
/**
144-
* Execute the Thread.
145-
*
146-
* Actually creates the native thread and starts it.
147-
* The native thread will start executing this Thread's
148-
* #__run__ method.
149-
*
150-
* @see Thread::allocate()
151-
*
152-
* @see kernel/thread.rb
153-
*/
154-
// Rubinius.primitive :thread_fork
155-
Object* fork(STATE);
156-
157-
/**
158-
* Execute the Thread.
159-
*
160-
* This leaves the thread in an attached state, so that
161-
* a pthread_join() later on will work.
162-
*/
163-
int fork_attached(STATE);
134+
void fork(STATE);
164135

165136
/**
166137
* Retrieve the priority set for this Thread.
@@ -178,15 +149,6 @@ namespace rubinius {
178149
// Rubinius.primitive :thread_raise
179150
Object* raise(STATE, Exception* exc);
180151

181-
// Rubinius.primitive :thread_set_exception
182-
Object* set_exception(STATE, Exception* exc);
183-
184-
/**
185-
* Returns current exception
186-
*/
187-
// Rubinius.primitive :thread_current_exception
188-
Object* current_exception(STATE);
189-
190152
/**
191153
* Kill this Thread.
192154
*/
@@ -222,9 +184,6 @@ namespace rubinius {
222184
// Rubinius.primitive :thread_join
223185
Thread* join(STATE, Object* timeout);
224186

225-
// Rubinius.primitive :thread_unlock_locks
226-
Object* unlock_locks(STATE);
227-
228187
// This method must only be called after fork() with only one active
229188
// thread.
230189
void unlock_after_fork(STATE);

‎machine/capi/thread.cpp

+14-37
Original file line numberDiff line numberDiff line change
@@ -239,13 +239,14 @@ extern "C" {
239239
Object* run_function(STATE) {
240240
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
241241

242-
Thread* self = state->vm()->thread.get();
242+
Thread* thread = state->vm()->thread.get();
243243

244-
NativeMethod* nm = capi::c_as<NativeMethod>(self->locals_aref(state, state->symbol("function")));
245-
Pointer* ptr = capi::c_as<Pointer>(self->locals_aref(state, state->symbol("argument")));
244+
NativeMethod* nm = capi::c_as<NativeMethod>(
245+
thread->locals_aref(state, state->symbol("function")));
246+
Pointer* ptr = capi::c_as<Pointer>(thread->locals_aref(state, state->symbol("argument")));
246247

247-
self->locals_remove(state, state->symbol("function"));
248-
self->locals_remove(state, state->symbol("argument"));
248+
thread->locals_remove(state, state->symbol("function"));
249+
thread->locals_remove(state, state->symbol("argument"));
249250

250251
NativeMethodFrame nmf(env, 0, nm);
251252
CallFrame* previous_frame = 0;
@@ -267,19 +268,14 @@ extern "C" {
267268
state->vm()->push_call_frame(&cf, previous_frame);
268269

269270
nmf.setup(
270-
env->get_handle(self),
271+
env->get_handle(thread),
271272
env->get_handle(cNil),
272273
env->get_handle(nm),
273274
env->get_handle(nm->module()));
274275

275-
{
276-
OnStack<3> os(state, self, nm, ptr);
277-
self->hard_unlock(state);
278-
}
279-
280276
ENTER_CAPI(state);
281277

282-
Object* ret = NULL;
278+
Object* value = NULL;
283279

284280
ExceptionPoint ep(env);
285281

@@ -288,24 +284,11 @@ extern "C" {
288284
if(unlikely(ep.jumped_to())) {
289285
LEAVE_CAPI(state);
290286

291-
state->vm()->pop_call_frame(previous_frame);
292-
293-
// Setup exception in thread so it's raised when joining
294-
// Reload self because it might have been moved
295-
self = state->vm()->thread.get();
296-
297-
{
298-
OnStack<1> os(state, self);
299-
self->hard_lock(state, false);
300-
Exception* exc = capi::c_as<Exception>(self->current_exception(state));
301-
self->exception(state, exc);
302-
self->alive(state, cFalse);
303-
self->hard_unlock(state);
304-
}
305-
306-
return NULL;
287+
// Set exception in thread so it's raised when joining.
288+
state->vm()->thread.get()->exception(state,
289+
capi::c_as<Exception>(state->vm()->thread_state()->current_exception()));
307290
} else {
308-
ret = env->get_object(nm->func()(ptr->pointer));
291+
value = env->get_object(nm->func()(ptr->pointer));
309292
}
310293

311294
LEAVE_CAPI(state);
@@ -316,15 +299,9 @@ extern "C" {
316299
env->set_current_native_frame(nmf.previous());
317300
ep.pop(env);
318301

319-
self = state->vm()->thread.get();
320-
321-
OnStack<1> os(state, self);
302+
state->vm()->thread.get()->alive(state, cFalse);
322303

323-
self->hard_lock(state, false);
324-
self->alive(state, cFalse);
325-
self->hard_unlock(state);
326-
327-
return ret;
304+
return value;
328305
}
329306

330307
VALUE capi_thread_create(VALUE (*func)(ANYARGS), void* arg, const char* name, const char* file) {

0 commit comments

Comments
 (0)
Please sign in to comment.