Граф коммитов

102 Коммитов

Автор SHA1 Сообщение Дата
Koichi Sasada 24f018972b fix timing bug
ractor_sleep() can remain wait.status by interrupt, so that this
patch handles more correctly.

This patch fixed this kind of assertion failures:

   Assertion Failed: ../src/ractor.c:1332:ractor_yield_atexit:cr->sync.wait.status == wait_none
2020-12-17 00:34:30 +09:00
Koichi Sasada a9a7f4d8b8 Ractor#receive_if to receive only matched messages
Instead of Ractor.receive, Ractor.receive_if can provide a pattern
by a block and you can choose the receiving message.

[Feature #17378]
2020-12-16 19:12:48 +09:00
Nobuyoshi Nakada 416e402cf3
Fixed a suspicious comparison 2020-12-13 13:12:18 +09:00
Koichi Sasada ee194af2aa re-layout rb_ractor_t
separate synchronization data and ractor local data.
2020-12-09 01:40:38 +09:00
Koichi Sasada c2fa024e02 fix Thread's interrupt and Ractor#take issue
Thread's interrupt set Ractor's wakeup_status as interrupted, but
the status remains next Ractor communication API. This patch makes
to ignore the previous interrupt state.
[Bug #17366]

Also this patch solves the Thread#kill and Ractor#take issues.
2020-12-07 16:01:35 +09:00
Koichi Sasada bef3eb5440 fix decl of ruby_single_main_ractor
On windows, MJIT doesn't work without this patch because of
the declaration of ruby_single_main_ractor. This patch fix this
issue and move the definition of it from ractor.c to vm.c to locate
near place of ruby_current_vm_ptr.
2020-12-07 08:28:36 +09:00
Koichi Sasada 91d99025e4 per-ractor object allocation
Now object allocation requires VM global lock to synchronize objspace.
However, of course, it introduces huge overhead.
This patch caches some slots (in a page) by each ractor and use cached
slots for object allocation. If there is no cached slots, acquire the global lock
and get new cached slots, or start GC (marking or lazy sweeping).
2020-12-07 08:28:36 +09:00
Koichi Sasada 307732ccee cancel theap on multi-ractors
accessing theap needs complicating synchronization but it reduce
performance on multi-ractor mode. So simply stop using theap
on multi-ractor mode. In future, theap should be replaced with
more cleaver memory strategy.
2020-12-07 08:28:36 +09:00
Koichi Sasada b67b24d0f5 ruby_single_main_ractor for single ractor mode
ruby_multi_ractor was a flag that indicates the interpreter doesn't
make any additional ractors (single ractor mode).
Instead of boolean flag, ruby_single_main_ractor pointer is introduced
which keeps main ractor's pointer if single ractor mode. If additional
ractors are created, ruby_single_main_ractor becomes NULL.
2020-12-07 08:28:36 +09:00
Koichi Sasada 82bbce826f fix index
`i` should not be used here because `i` will be `alen` when
jumped here by "goto restart".
2020-12-04 14:42:38 +09:00
Takashi Kokubun 58c3c75fee
Skip checking Ractor recursive locking
for an MJIT worker thread. We can't do it because its GET_EC() returns
NULL.
2020-12-02 23:38:42 -08:00
Koichi Sasada 764de7566f should not use rb_str_modify(), too
Same as 8247b8edde, should not use rb_str_modify() here.

https://bugs.ruby-lang.org/issues/17343#change-88858
2020-12-01 18:16:23 +09:00
Koichi Sasada 182fb73c40 rb_ext_ractor_safe() to declare ractor-safe ext
C extensions can violate the ractor-safety, so only ractor-safe
C extensions (C methods) can run on non-main ractors.
rb_ext_ractor_safe(true) declares that the successive
defined methods are ractor-safe. Otherwiwze, defined methods
checked they are invoked in main ractor and raise an error
if invoked at non-main ractors.

[Feature #17307]
2020-12-01 15:44:18 +09:00
Koichi Sasada 8247b8edde should not use rb_ary_modify()
ractor_copy() used rb_ary_modify() to make sure this array is not
sharing anything, but it also checks frozen flag. So frozen arrays
raises an error. To solve this issue, this patch introduces new
function rb_ary_cancel_sharing() which makes sure the array does not
share another array and it doesn't check frozen flag.
[Bug #17343]

A test is quoted from https://github.com/ruby/ruby/pull/3817
2020-12-01 13:18:32 +09:00
Koichi Sasada 67693d8d80 ractor local storage C-API
To manage ractor-local data for C extension, the following APIs
are defined.

* rb_ractor_local_storage_value_newkey
* rb_ractor_local_storage_value
* rb_ractor_local_storage_value_set
* rb_ractor_local_storage_ptr_newkey
* rb_ractor_local_storage_ptr
* rb_ractor_local_storage_ptr_set

At first, you need to create a key of storage by
rb_ractor_local_(value|ptr)_newkey().
For ptr storage, it accepts the type of storage,
how to mark and how to free with ractor's lifetime.

rb_ractor_local_storage_value/set are used to access a VALUE
and rb_ractor_local_storage_ptr/set are used to access a pointer.

random.c uses this API.
2020-12-01 09:39:30 +09:00
Marc-Andre Lafortune e25165b3fc Fix `Ractor.make_shareable` for recursive structures with unfreezable components
Followup to #3823
2020-11-30 19:33:37 -05:00
Nobuyoshi Nakada 930a135524
Fixed Ractor.shareable? on cross-recursive objects [Bug #17344] 2020-11-30 16:07:36 +09:00
Nobuyoshi Nakada 039ba387aa
Use opaque struct pointer than void 2020-11-27 21:38:08 +09:00
Koichi Sasada 5496415d31 mark default_rand
default_rand can points a Bignum seed, so it should be marked.
2020-11-27 17:36:02 +09:00
Koichi Sasada 2db2fb9f6c per-ractor Random::DEFAULT
Random generators are not Ractor-safe, so we need to prepare
per-ractor default random genearators. This patch set
`Random::DEFAULT = Randm` (not a Random instance, but the Random
class) and singleton methods like `Random.rand()` use a per-ractor
random generator.

[Feature #17322]
2020-11-27 17:03:30 +09:00
Koichi Sasada d43d4acf26 fix error message 2020-11-25 15:51:31 +09:00
Koichi Sasada 5e3259ea74 fix public interface
To make some kind of Ractor related extensions, some functions
should be exposed.

* include/ruby/thread_native.h
  * rb_native_mutex_*
  * rb_native_cond_*
* include/ruby/ractor.h
  * RB_OBJ_SHAREABLE_P(obj)
  * rb_ractor_shareable_p(obj)
  * rb_ractor_std*()
  * rb_cRactor

and rm ractor_pub.h
and rename srcdir/ractor.h to srcdir/ractor_core.h
    (to avoid conflict with include/ruby/ractor.h)
2020-11-18 03:52:41 +09:00
Koichi Sasada deed21bb08 ignore yield_atexit if outgoing port is closed
If outgoing_port is closed, Ractor.yield never successes.
[Bug #17310]
2020-11-11 18:10:43 +09:00
Koichi Sasada db31ace934 Threads in a ractor will be killed with the ractor
If a terminating ractor has child threads, then kill all child
threads.
2020-11-11 15:49:02 +09:00
Koichi Sasada 7718e9588b a part of T_DATA object can Ractor#send
T_DATA objects can refer unshareable objects and they should be
copied recursively, however there is no way to replace with copied
unshareable objects. However, if a T_DATA object refers only
shareable objects, there is no need to replace. So this kind of
T_DATA object (such as Time, Dir, File::Status and so on) can be
sent by Ractor.send.
2020-11-06 16:14:36 +09:00
Nobuyoshi Nakada bdcfa70bbd
strip trailing spaces [ci skip] 2020-11-02 17:31:50 +09:00
Koichi Sasada 5fefb53249 Copy for Ractor.send() without marshal.
Now copying objects do not need marshal protocol.
2020-11-02 03:31:58 +09:00
Koichi Sasada db7a3b63ba suppport Ractor.send(move: true) for more deta
This patch allows to move more data types.
2020-11-02 01:37:28 +09:00
Koichi Sasada fd08927699 Ractor's "will" doesn't need copying.
`r = Ractor.new{ expr }` generates the block return value from `expr`
and we can get this value by `r.take`. Ractor.yield and Ractor#take
passing values by copying on default. However, the block return value
(we named it "will" in the code) is not referred from the Ractor
because the Ractor is already dead. So we can pass the reference
of "will" to another ractor without copying. We can apply same story
for the propagated exception.
2020-10-31 01:48:00 +09:00
Koichi Sasada 5d97bdc2dc Ractor.make_shareable(a_proc)
Ractor.make_shareable() supports Proc object if
(1) a Proc only read outer local variables (no assignments)
(2) read outer local variables are shareable.

Read local variables are stored in a snapshot, so after making
shareable Proc, any assignments are not affeect like that:

```ruby
a = 1
pr = Ractor.make_shareable(Proc.new{p a})
pr.call #=> 1
a = 2
pr.call #=> 1 # `a = 2` doesn't affect
```

[Feature #17284]
2020-10-30 03:12:09 +09:00
Koichi Sasada 603fb940c0 refactoring obj_traverse_i 2020-10-22 00:43:44 +09:00
Koichi Sasada 3a97d36157 refactoring frozen_shareable_p 2020-10-21 23:57:44 +09:00
Koichi Sasada 89f6644de7 refactoring rb_obj_traverse()
* create rec check hash lazily
* do not pass *data pointer for enter/leave function because
  it is not used.
2020-10-21 23:52:11 +09:00
Koichi Sasada 2f50936cb9 Ractor.make_shareable(obj)
Introduce new method Ractor.make_shareable(obj) which tries to make
obj shareable object. Protocol is here.

(1) If obj is shareable, it is shareable.
(2) If obj is not a shareable object and if obj can be shareable
    object if it is frozen, then freeze obj. If obj has reachable
    objects (rs), do rs.each{|o| Ractor.make_shareable(o)}
    recursively (recursion is not Ruby-level, but C-level).
(3) Otherwise, raise Ractor::Error. Now T_DATA is not a shareable
    object even if the object is frozen.

If the method finished without error, given obj is marked as
a sharable object.

To allow makng a shareable frozen T_DATA object, then set
`RUBY_TYPED_FROZEN_SHAREABLE` as type->flags. On default,
this flag is not set. It means user defined T_DATA objects are
not allowed to become shareable objects when it is frozen.

You can make any object  shareable by setting FL_SHAREABLE flag,
so if you know that the T_DATA object is shareable (== thread-safe),
set this flag, at creation time for example. `Ractor` object is one
example, which is not a frozen, but a shareable object.
2020-10-21 07:59:24 +09:00
Koichi Sasada 99310e3eb5 Some global variables can be accessed from ractors
Some global variables should be used from non-main Ractors.
[Bug #17268]

```ruby
     # ractor-local (derived from created ractor): debug
     '$DEBUG' => $DEBUG,
     '$-d' => $-d,

     # ractor-local (derived from created ractor): verbose
     '$VERBOSE' => $VERBOSE,
     '$-w' => $-w,
     '$-W' => $-W,
     '$-v' => $-v,

     # process-local (readonly): other commandline parameters
     '$-p' => $-p,
     '$-l' => $-l,
     '$-a' => $-a,

     # process-local (readonly): getpid
     '$$'  => $$,

     # thread local: process result
     '$?'  => $?,

     # scope local: match
     '$~'  => $~.inspect,
     '$&'  => $&,
     '$`'  => $`,
     '$\''  => $',
     '$+'  => $+,
     '$1'  => $1,

     # scope local: last line
     '$_' => $_,

     # scope local: last backtrace
     '$@' => $@,
     '$!' => $!,

     # ractor local: stdin, out, err
     '$stdin'  => $stdin.inspect,
     '$stdout' => $stdout.inspect,
     '$stderr' => $stderr.inspect,
```
2020-10-20 15:38:54 +09:00
tompng e8d03c9a2a change rb_ractor_queue to ring buffer 2020-10-12 14:20:58 +09:00
Benoit Daloze bfc1c7205d Add Ractor#receive and Ractor.receive and use it in all places
* Keep Ractor#recv/Ractor.recv as an alias for now.
2020-10-10 12:48:09 +02:00
Koichi Sasada a770b9c87e remove debug code 2020-10-10 04:46:09 +09:00
Koichi Sasada 96739c4222 Frozen Struct can be shareable.
A frozen Struct object which refers to shareable objects should be
shareable.
2020-09-25 16:00:13 +09:00
Koichi Sasada d247dedade Ractor.yield should raise if out-port is closed
Ractor.yield should raise Ractor::ClosedError if current Ractor's
outgoing-port is closed.
2020-09-25 12:53:58 +09:00
Koichi Sasada 5286526346 frozen T_OBJECT can be shareable.
If an T_OBJECT object is frozen and all ivars are shareable,
the object should be shareable.
2020-09-25 12:52:53 +09:00
Koichi Sasada 7ad3aff48d Ractor#close_outgoping cancel Ractor.yield
Ractor#close_outgoing should cancel waiting Ractor.yield. However,
yield a value by the Ractor's block should not cancel (to recognize
terminating Ractor, introduce rb_ractor_t::yield_atexit flag).
2020-09-25 00:25:38 +09:00
Koichi Sasada 29ed16ff4a add GC_GUARD
We observed mark miss on this point so we add RB_GC_GUARD() to
avoid wrong free.
2020-09-24 17:09:12 +09:00
Quang-Minh Nguyen 398da71175 Validate name during initialization 2020-09-20 23:10:44 +09:00
Nobuyoshi Nakada 702cebf104
strip trailing spaces [ci skip] 2020-09-19 17:40:54 +09:00
Koichi Sasada b416a76402 add debug log on enabling multi-ractor mode 2020-09-18 14:17:49 +09:00
Koichi Sasada f7ccb8dd88 restart Ractor.select on intterupt
signal can interrupt Ractor.select, but if there is no exception,
Ractor.select should restart automatically.
2020-09-15 00:04:59 +09:00
Kazuhiro NISHIYAMA 776b3df490
Fix typos [ci skip] 2020-09-06 01:58:44 +09:00
Nobuyoshi Nakada d164eef957
Fixed heap-use-after-free on racter 2020-09-04 15:17:42 +09:00
Koichi Sasada 3b0bcaf287 check multi_ractor mode at main_p
rb_ractor_main_p() need to access to the ractor pointer in TLS.
However it is slow operation so that we need to skip this check
if it is not multi-ractor mode (!ruby_multi_ractor).

This performance regression is pointed at
https://bugs.ruby-lang.org/issues/17100#note-27
2020-09-04 14:18:48 +09:00
Nobuyoshi Nakada 169b1d1aca
Initialize loop variables of list_for_each for MS VC 2020-09-04 11:46:50 +09:00
Koichi Sasada 79df14c04b Introduce Ractor mechanism for parallel execution
This commit introduces Ractor mechanism to run Ruby program in
parallel. See doc/ractor.md for more details about Ractor.
See ticket [Feature #17100] to see the implementation details
and discussions.

[Feature #17100]

This commit does not complete the implementation. You can find
many bugs on using Ractor. Also the specification will be changed
so that this feature is experimental. You will see a warning when
you make the first Ractor with `Ractor.new`.

I hope this feature can help programmers from thread-safety issues.
2020-09-03 21:11:06 +09:00