[#50466] [ruby-trunk - Bug #7492][Open] Segmentation fault at DL::TestDL#test_call_double on x64 Windows 8 — "phasis68 (Heesob Park)" <phasis@...>
23 messages
2012/12/02
[#59083] [ruby-trunk - Bug #7492] Segmentation fault at DL::TestDL#test_call_double on x64 Windows 8
— "phasis68 (Heesob Park)" <phasis@...>
2013/12/13
[#50483] [IMPORTANT] 2.0.0 release plan — Yusuke Endoh <mame@...>
ALL COMMITTERS SHOULD READ THIS MAIL! コミッタはこのメール読んで!
5 messages
2012/12/02
[#50561] [ruby-trunk - Bug #7513][Open] TracePoint#enable/disable should not cause error — "ko1 (Koichi Sasada)" <redmine@...>
7 messages
2012/12/05
[#50575] [ruby-trunk - Feature #7517][Open] Fixnum::MIN,MAX — "matz (Yukihiro Matsumoto)" <matz@...>
20 messages
2012/12/05
[#50593] [ruby-trunk - Feature #7517] Fixnum::MIN,MAX
— "shyouhei (Shyouhei Urabe)" <shyouhei@...>
2012/12/05
[#50594] Re: [ruby-trunk - Feature #7517] Fixnum::MIN,MAX
— Charles Oliver Nutter <headius@...>
2012/12/05
On Wed, Dec 5, 2012 at 12:24 PM, shyouhei (Shyouhei Urabe)
[#50636] [ruby-trunk - Bug #7528][Open] CSV.== fails to check object type — "SteveW (Stephen Wattam)" <stephenwattam@...>
6 messages
2012/12/06
[#50645] [ruby-trunk - Bug #7530][Open] Concurrent loads fail with mutex errors — "headius (Charles Nutter)" <headius@...>
7 messages
2012/12/06
[#50660] [ruby-trunk - Feature #4085] Refinements and nested methods — "trans (Thomas Sawyer)" <transfire@...>
3 messages
2012/12/07
[#50699] Commit access for Yehuda Katz — Aaron Patterson <tenderlove@...>
Hi,
4 messages
2012/12/08
[#50923] Re: Commit access for Yehuda Katz
— Charles Oliver Nutter <headius@...>
2012/12/16
I will +1 this, unsure if it has happened already (it's "catch up on
[#50733] [ruby-trunk - Bug #7539][Open] Misleading error message "can't convert nil into string" — "connec (Chris Connelly)" <chris@...>
8 messages
2012/12/10
[#50755] Becoming a committer — Charlie Somerville <charlie@...>
Hi ruby-core,
21 messages
2012/12/11
[#50759] Re: Becoming a committer
— Yukihiro Matsumoto <matz@...>
2012/12/11
Hi,
[#50784] Re: Becoming a committer
— Charles Oliver Nutter <headius@...>
2012/12/11
It's really this easy? If so, I'll send over my public key today :)
[#50795] Re: Becoming a committer
— Yukihiro Matsumoto <matz@...>
2012/12/11
Hi,
[#50797] Re: Becoming a committer
— Charles Oliver Nutter <headius@...>
2012/12/11
I guess there's a few things I'd be interested in:
[#50809] Re: Becoming a committer
— SASADA Koichi <ko1@...>
2012/12/12
(2012/12/12 8:55), Charles Oliver Nutter wrote:
[#50815] Re: Becoming a committer
— Charles Oliver Nutter <headius@...>
2012/12/12
On Wed, Dec 12, 2012 at 12:04 AM, SASADA Koichi <[email protected]> wrote:
[#50816] Re: Becoming a committer
— "NARUSE, Yui" <naruse@...>
2012/12/12
2012/12/12 Charles Oliver Nutter <[email protected]>:
[#50817] Re: Becoming a committer
— Charles Oliver Nutter <headius@...>
2012/12/12
On Wed, Dec 12, 2012 at 2:59 AM, NARUSE, Yui <[email protected]> wrote:
[#50765] [ruby-trunk - Bug #7544][Open] Accented characters in IRB — cfabianski (Cédric FABIANSKI) <cfabianski@...>
6 messages
2012/12/11
[#50793] [ruby-trunk - Bug #7547][Open] Dir.mktmpdir('~something') tries to expand a profile directory — "jstanley0 (Jeremy Stanley)" <jeremy@...>
4 messages
2012/12/11
[#50810] [ruby-trunk - Feature #7549][Open] A Ruby Design Process — "brixen (Brian Ford)" <brixen@...>
34 messages
2012/12/12
[#50829] [ruby-trunk - Feature #7549] A Ruby Design Process
— "subwindow (Erik Peterson)" <erik@...>
2012/12/12
[#50837] [ruby-trunk - Feature #7549] A Ruby Design Process
— "subwindow (Erik Peterson)" <erik@...>
2012/12/12
[#50867] [ruby-trunk - Bug #7556][Assigned] test error on refinement — "usa (Usaku NAKAMURA)" <usa@...>
14 messages
2012/12/13
[#50900] [ruby-trunk - Bug #7564][Open] r38175 introduces incompatibility — "tenderlovemaking (Aaron Patterson)" <aaron@...>
14 messages
2012/12/14
[#50913] [ruby-trunk - Bug #7568][Open] Yaml fails to encode zero date string. — "anshul (Anshul Khandelwal)" <anshul@...>
5 messages
2012/12/15
[#50920] [ruby-trunk - Bug #7568][Assigned] Yaml fails to encode zero date string.
— "charliesome (Charlie Somerville)" <charlie@...>
2012/12/16
[#50988] Re: [ruby-trunk - Bug #7568][Assigned] Yaml fails to encode zero date string.
— Aaron Patterson <tenderlove@...>
2012/12/19
On Sun, Dec 16, 2012 at 12:53:14PM +0900, charliesome (Charlie Somerville) wrote:
[#51015] 1.9.3 patch level release — Zachary Scott <zachary@...>
I know unak-san was asking about a 1.9.3 patch level release, so I
8 messages
2012/12/20
[#51099] [ruby-trunk - Feature #7612][Open] Enumerators take a proc — "pedz (Perry Smith)" <pedz@...>
4 messages
2012/12/23
[ruby-core:50508] [ruby-trunk - Feature #6762] Control interrupt timing
From:
"ko1 (Koichi Sasada)" <redmine@...>
Date:
2012-12-03 07:02:30 UTC
List:
ruby-core #50508
Issue #6762 has been updated by ko1 (Koichi Sasada).
brent (Brent Roman) wrote:
> OK. I see the logic in using the term "interrupt" if you are actually
> trying to unify exceptions from other threads with handling of OS
> signals. However, both of these are generally thought of as being
> asynchronous events.
I agree. They are "asynchronous events".
> Try googling (with the quotes):
>
> "asynchronous interrupt*" => 1,130,000 results
> "synchronous interrupt*" => 180,000 results
>
> If you insist on the async_* prefix, you should apply it consistently.
> But, Thread.control_async_interrupt( is getting quite cumbersome, no?
You are right.
> As someone who was writing ISRs for Intel 8080's and Zilog Z-80's in the
> late 1970's, here are my suggestions for more conventional vocabulary:
>
> Thread.control_interrupt becomes Thread.interruptible
> alternatives would be:
> Thread.allow_interrupt or Thread.enable_interrupt
> Any of these read better (to a native English speaker).
> I like interruptible because it is a *property* of the thread being
> assigned by the construct. After all, nothing actually happens when
> this construct is executed. It affects what (might) happen later:
>
> th = Thread.new{
> Thread.interruptible(RuntimeError => :on_blocking){
> ...
> }
"interruptible" makes sense for me.
But I feel it is ambiguous that this method returns only current interruptible flags.
How about to use `async_event' ?
> In General:
> Code within the block passed to the Thread.interruptible method may
> or may not be interrupted according to the specification passed as its
> Hash argument.
>
> In the example above, within the block passed to Thread.interruptible,
> the thread becomes interruptible by any RuntimeError when/if
> it waits for I/O or stops.
>
> =====
>
> The method :async_interrupted? would be better named:
> :interrupts_pending?
> A thread is not interrupted if it has interrupts being deferred.
> The accepted idiom for this is is to say the thread has interrupts
> pending for it.
As non-native English speaker, I'm not sure the difference with "pending_interrupt?". Yours is good?
> The use case for defining interrupts_pending? method as Thread instance
> method is summarized on one word: debugging!
It makes sense.
> If you have a complex application that has threads which seem to be
> unresponsive, you'll want some way to tell whether those threads are
> ignoring pending interrupts, or whether they are not even getting
> interrupts delivered to them.
>
> I'd also suggest adding another method:
>
> Thread#interrupts_pending #without the question mark
>
> This would return the number of pending interrupts for the thread.
> A thread might normally have 0, 1 or 2 pending interrupts. Seeing
> dozens pending would indicate a performance problem. This would be
> very useful information for debugging and optimization. A thread might
> even decide to take some drastic action to if it discovers that it has
> too many interrupts pending for itself.
I don't like this method.
I like Thread#interrupts_pending?(err_class) what current Thread#async_interrupt? do.
Number is important? I don't think so.
> Making Thread.current.raise act like sending exceptions to any other
> thread seemed more consistent to me because the method's behavior then
> has no special case for Thread.current. I have written low level code
> what processed a hardware interrupt, but then decided it must defer it
> for later and accomplished this by making the interrupt pending again,
> in the controller chip, but masked the interrupt in the CPU. However, I
> can see where this might break existing code that currently relies on
> Thread.current#raise being exactly synonymous with Kernel#raise
> Either behavior is workable.
I agree with it. Non *exception* is easy to understand.
Guys: any problem on it?
----------------------------------------
Feature #6762: Control interrupt timing
https://bugs.ruby-lang.org/issues/6762#change-34348
Author: ko1 (Koichi Sasada)
Status: Feedback
Priority: High
Assignee: ko1 (Koichi Sasada)
Category: core
Target version: 2.0.0
=begin
= Abstract
Add asynchronous interrupt timing control feature. Control with the following three modes:
* immediate: process interrupt immediately
* never: never process interrupt
* on_blocking: delay interrupt until blocking operation
# example
th = Thread.new do
Thread.control_interrupt(RuntimeError => :never) do
# in this block, thrown RuntimeError doesn't occur
end
... # raise thrown RuntimeError
end
...
th.raise "foo"
= Background
== Terminology
* Interrupt: asynchronous interrupt and corresponding procedures
* Thread#raise and occurring exception
* signal and corresponding trap
* Thread#kill and thread termination
* Main thread termination and thread termination
(after main thread termination, all threads exit themselves)
* Interrupt checking: check interrupt
* Blocking operation: Possible to block the current thread such as IO read/write. In CRuby implementation, it is nearly equals to tasks without GVL
== Current use-cases of Interrupt
There are several `Interrupt' in Ruby.
# Example 1
th = Thread.new{
begin
...
rescue FooError
...
end
}
th.raise(FooError) #=> Raise FooError on thread `th'
# Example 2
q = Queue.new
th1 = Thread.new{
q << calc_in_algorithm1
}
th2 = Thread.new{
q << calc_in_algorithm2
}
result = q.pop
th1.raise(TerminateCalcError)
th2.raise(TerminateCalcError)
# Run two algorithms simultaneously.
# If we get an answer from one algorithm,
# kill them with TerminateCalcError
# In this case, it is also okay with Thread#kill
# Example 3
trap(SIGINT){
# do something
# maybe termination process
}
trap(SIGHUP){
# do something
# maybe reloading configuration process
}
server_exec # server main process
In such interrupts are checked at several points such as:
* method invocation timing
* method returning timing
* move program counter
* before and after block operation
== Problem
Interrupt causes the following problems because we can't control occurring timing.
* Un-safe ensure clause: Generally, ensure clause should not interrupt because it contains important tasks such as freeing resources.
* Un-safe resource allocation: If interrupt occurs between resource allocation and assign it to the variable, we can't free this object (however, this problem not too big because we have a gc and appropriate finalizer can free it).
* (other problems? please complement me)
I show an example below.
# Example 4
# this method is similar implementation of timeout()
def timeout(sec)
timer_thread = Thread.new(Thread.current){|parent|
sleep(sec)
parent.raise(TimeoutError)
}
begin
yield
ensure
timer_thread.stop # close thread
end
end
timeout(3){
begin
f = # point (a)
open(...) # of course, there are no problem with open(...){|f| ...}
# but it is an example to show the problem
...
ensure
... # point (b)
f.close
end
}
On example 4, there are two problems.
Point (b) is easy to understand. If interrupt was thrown at point (b), then `f.close()' isn't called. It is problem.
On the point (a), it is a position between resource allocation (open()) and assignment `f = '. It is very rare, but it is possible. If we get interrupt before assignment, then we can't free resources (can't call f.close()) in ensure clause. It is also problem.
The problem is we can't control interrupt timing.
= Proposal
Adding interrupt timing control feature to Thread. Introduce two methods to Thread class.
* Thread.control_interrupt
* Thread.check_interrupt
Rdoc documents are:
Thread.control_interrupt():
call-seq:
Thread.control_interrupt(hash) { ... } -> result of the block
Thread.control_interrupt controls interrupt timing.
_interrupt_ means asynchronous event and corresponding procedure
by Thread#raise, Thread#kill, signal trap (not supported yet)
and main thread termination (if main thread terminates, then all
other thread will be killed).
_hash_ has pairs of ExceptionClass and TimingSymbol. TimingSymbol
is one of them:
- :immediate Invoke interrupt immediately.
- :on_blocking Invoke interrupt while _BlockingOperation_.
- :never Never invoke interrupt.
_BlockingOperation_ means that the operation will block the calling thread,
such as read and write. On CRuby implementation, _BlockingOperation_ is
operation executed without GVL.
Masked interrupts are delayed until they are enabled.
This method is similar to sigprocmask(3).
TODO (DOC): control_interrupt is stacked.
TODO (DOC): check ancestors.
TODO (DOC): to prevent all interrupt, {Object => :never} works.
NOTE: Asynchronous interrupts are difficult to use.
If you need to communicate between threads,
please consider to use another way such as Queue.
Or use them with deep understanding about this method.
# example: Guard from Thread#raise
th = Thread.new do
Thead.control_interrupt(RuntimeError => :never) {
begin
# Thread#raise doesn't interrupt here.
# You can write resource allocation code safely.
Thread.control_interrupt(RuntimeError => :immediate) {
# ...
# It is possible to be interrupted by Thread#raise.
}
ensure
# Thread#raise doesn't interrupt here.
# You can write resource dealocation code safely.
end
}
end
Thread.pass
# ...
th.raise "stop"
# example: Guard from TimeoutError
require 'timeout'
Thread.control_interrupt(TimeoutError => :never) {
timeout(10){
# TimeoutError doesn't occur here
Thread.control_interrupt(TimeoutError => :on_blocking) {
# possible to be killed by TimeoutError
# while blocking operation
}
# TimeoutError doesn't occur here
}
}
# example: Stack control settings
Thread.control_interrupt(FooError => :never) {
Thread.control_interrupt(BarError => :never) {
# FooError and BarError are prohibited.
}
}
# example: check ancestors
Thread.control_interrupt(Exception => :never) {
# all exceptions inherited from Exception are prohibited.
}
Thread.check_interrupt():
call-seq:
Thread.check_interrupt() -> nil
Check queued interrupts.
If there are queued interrupts, process respective procedures.
This method can be defined as the following Ruby code:
def Thread.check_interrupt
Thread.control_interrupt(Object => :immediate) {
Thread.pass
}
end
Examples:
th = Thread.new{
Thread.control_interrupt(RuntimeError => :on_blocking){
while true
...
# reach safe point to invoke interrupt
Thread.check_interrupt
...
end
}
}
...
th.raise # stop thread
NOTE: This example can be described by the another code.
You need to keep to avoid asynchronous interrupts.
flag = true
th = Thread.new{
Thread.control_interrupt(RuntimeError => :on_blocking){
while true
...
# reach safe point to invoke interrupt
break if flag == false
...
end
}
}
...
flag = false # stop thread
I have already commit-ed these methods into trunk.
Please try it and discuss.
This commit is easy to revert :)
Naming is also problem as usual. Good naming is also welcome.
= Acknowledgment
The base of this proposal is a discussion[1].
[1] Akira Tanaka "Re: Thread#raise, Thread#kill, and timeout.rb are
unsafe" ruty-talk (2008.3) <http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/294917>
Many dev-people help me to make up this proposal.
=end
--
http://bugs.ruby-lang.org/