@@ -241,12 +241,17 @@ struct rb_fiber_struct {
241
241
*/
242
242
unsigned int transferred : 1 ;
243
243
244
+ /* Whether the fiber is allowed to implicitly yield. */
245
+ unsigned int blocking : 1 ;
246
+
244
247
struct coroutine_context context ;
245
248
struct fiber_pool_stack stack ;
246
249
};
247
250
248
251
static struct fiber_pool shared_fiber_pool = {NULL , NULL , 0 , 0 , 0 , 0 };
249
252
253
+ static ID fiber_initialize_keywords [2 ] = {0 };
254
+
250
255
/*
251
256
* FreeBSD require a first (i.e. addr) argument of mmap(2) is not NULL
252
257
* if MAP_STACK is passed.
@@ -1733,7 +1738,7 @@ fiber_alloc(VALUE klass)
1733
1738
}
1734
1739
1735
1740
static rb_fiber_t *
1736
- fiber_t_alloc (VALUE fiber_value )
1741
+ fiber_t_alloc (VALUE fiber_value , unsigned int blocking )
1737
1742
{
1738
1743
rb_fiber_t * fiber ;
1739
1744
rb_thread_t * th = GET_THREAD ();
@@ -1746,6 +1751,7 @@ fiber_t_alloc(VALUE fiber_value)
1746
1751
fiber = ZALLOC (rb_fiber_t );
1747
1752
fiber -> cont .self = fiber_value ;
1748
1753
fiber -> cont .type = FIBER_CONTEXT ;
1754
+ fiber -> blocking = blocking ;
1749
1755
cont_init (& fiber -> cont , th );
1750
1756
1751
1757
fiber -> cont .saved_ec .fiber_ptr = fiber ;
@@ -1763,9 +1769,9 @@ fiber_t_alloc(VALUE fiber_value)
1763
1769
}
1764
1770
1765
1771
static VALUE
1766
- fiber_initialize (VALUE self , VALUE proc , struct fiber_pool * fiber_pool )
1772
+ fiber_initialize (VALUE self , VALUE proc , struct fiber_pool * fiber_pool , unsigned int blocking )
1767
1773
{
1768
- rb_fiber_t * fiber = fiber_t_alloc (self );
1774
+ rb_fiber_t * fiber = fiber_t_alloc (self , blocking );
1769
1775
1770
1776
fiber -> first_proc = proc ;
1771
1777
fiber -> stack .base = NULL ;
@@ -1793,17 +1799,66 @@ fiber_prepare_stack(rb_fiber_t *fiber)
1793
1799
sec -> local_storage_recursive_hash_for_trace = Qnil ;
1794
1800
}
1795
1801
1802
+ static struct fiber_pool *
1803
+ rb_fiber_pool_default (VALUE pool )
1804
+ {
1805
+ return & shared_fiber_pool ;
1806
+ }
1807
+
1808
+ /* :nodoc: */
1809
+ static VALUE
1810
+ rb_fiber_initialize_kw (int argc , VALUE * argv , VALUE self , int kw_splat )
1811
+ {
1812
+ VALUE pool = Qnil ;
1813
+ VALUE blocking = Qtrue ;
1814
+
1815
+ if (kw_splat != RB_NO_KEYWORDS ) {
1816
+ VALUE options = Qnil ;
1817
+ VALUE arguments [2 ] = {Qundef };
1818
+
1819
+ argc = rb_scan_args_kw (kw_splat , argc , argv , ":" , & options );
1820
+ rb_get_kwargs (options , fiber_initialize_keywords , 0 , 2 , arguments );
1821
+
1822
+ blocking = arguments [0 ];
1823
+ pool = arguments [1 ];
1824
+ }
1825
+
1826
+ return fiber_initialize (self , rb_block_proc (), rb_fiber_pool_default (pool ), RTEST (blocking ));
1827
+ }
1828
+
1796
1829
/* :nodoc: */
1797
1830
static VALUE
1798
1831
rb_fiber_initialize (int argc , VALUE * argv , VALUE self )
1799
1832
{
1800
- return fiber_initialize ( self , rb_block_proc (), & shared_fiber_pool );
1833
+ return rb_fiber_initialize_kw ( argc , argv , self , rb_keyword_given_p () );
1801
1834
}
1802
1835
1803
1836
VALUE
1804
1837
rb_fiber_new (rb_block_call_func_t func , VALUE obj )
1805
1838
{
1806
- return fiber_initialize (fiber_alloc (rb_cFiber ), rb_proc_new (func , obj ), & shared_fiber_pool );
1839
+ return fiber_initialize (fiber_alloc (rb_cFiber ), rb_proc_new (func , obj ), rb_fiber_pool_default (Qnil ), 1 );
1840
+ }
1841
+
1842
+ static VALUE
1843
+ rb_f_fiber_kw (int argc , VALUE * argv , int kw_splat )
1844
+ {
1845
+ rb_thread_t * th = GET_THREAD ();
1846
+ VALUE scheduler = th -> scheduler ;
1847
+ VALUE fiber = Qnil ;
1848
+
1849
+ if (scheduler != Qnil ) {
1850
+ fiber = rb_funcall_passing_block_kw (scheduler , rb_intern ("fiber" ), argc , argv , kw_splat );
1851
+ } else {
1852
+ rb_raise (rb_eRuntimeError , "No scheduler is available!" );
1853
+ }
1854
+
1855
+ return fiber ;
1856
+ }
1857
+
1858
+ static VALUE
1859
+ rb_f_fiber (int argc , VALUE * argv , VALUE obj )
1860
+ {
1861
+ return rb_f_fiber_kw (argc , argv , rb_keyword_given_p ());
1807
1862
}
1808
1863
1809
1864
static void rb_fiber_terminate (rb_fiber_t * fiber , int need_interrupt );
@@ -1820,6 +1875,10 @@ rb_fiber_start(void)
1820
1875
VM_ASSERT (th -> ec == ruby_current_execution_context_ptr );
1821
1876
VM_ASSERT (FIBER_RESUMED_P (fiber ));
1822
1877
1878
+ if (fiber -> blocking ) {
1879
+ th -> blocking += 1 ;
1880
+ }
1881
+
1823
1882
EC_PUSH_TAG (th -> ec );
1824
1883
if ((state = EC_EXEC_TAG ()) == TAG_NONE ) {
1825
1884
rb_context_t * cont = & VAR_FROM_MEMORY (fiber )-> cont ;
@@ -1892,6 +1951,7 @@ rb_threadptr_root_fiber_setup(rb_thread_t *th)
1892
1951
fiber -> cont .type = FIBER_CONTEXT ;
1893
1952
fiber -> cont .saved_ec .fiber_ptr = fiber ;
1894
1953
fiber -> cont .saved_ec .thread_ptr = th ;
1954
+ fiber -> blocking = 1 ;
1895
1955
fiber_status_set (fiber , FIBER_RESUMED ); /* skip CREATED */
1896
1956
th -> ec = & fiber -> cont .saved_ec ;
1897
1957
}
@@ -2044,11 +2104,15 @@ fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int is_resume, int
2044
2104
}
2045
2105
}
2046
2106
2107
+ VM_ASSERT (FIBER_RUNNABLE_P (fiber ));
2108
+
2047
2109
if (is_resume ) {
2048
2110
fiber -> prev = fiber_current ();
2049
2111
}
2050
2112
2051
- VM_ASSERT (FIBER_RUNNABLE_P (fiber ));
2113
+ if (fiber_current ()-> blocking ) {
2114
+ th -> blocking -= 1 ;
2115
+ }
2052
2116
2053
2117
cont -> argc = argc ;
2054
2118
cont -> kw_splat = kw_splat ;
@@ -2060,6 +2124,10 @@ fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int is_resume, int
2060
2124
fiber_stack_release (fiber );
2061
2125
}
2062
2126
2127
+ if (fiber_current ()-> blocking ) {
2128
+ th -> blocking += 1 ;
2129
+ }
2130
+
2063
2131
RUBY_VM_CHECK_INTS (th -> ec );
2064
2132
2065
2133
EXEC_EVENT_HOOK (th -> ec , RUBY_EVENT_FIBER_SWITCH , th -> self , 0 , 0 , 0 , Qnil );
@@ -2073,6 +2141,12 @@ rb_fiber_transfer(VALUE fiber_value, int argc, const VALUE *argv)
2073
2141
return fiber_switch (fiber_ptr (fiber_value ), argc , argv , 0 , RB_NO_KEYWORDS );
2074
2142
}
2075
2143
2144
+ VALUE
2145
+ rb_fiber_blocking_p (VALUE fiber )
2146
+ {
2147
+ return (fiber_ptr (fiber )-> blocking == 0 ) ? Qfalse : Qtrue ;
2148
+ }
2149
+
2076
2150
void
2077
2151
rb_fiber_close (rb_fiber_t * fiber )
2078
2152
{
@@ -2442,6 +2516,9 @@ Init_Cont(void)
2442
2516
2443
2517
fiber_pool_initialize (& shared_fiber_pool , stack_size , FIBER_POOL_INITIAL_SIZE , vm_stack_size );
2444
2518
2519
+ fiber_initialize_keywords [0 ] = rb_intern_const ("blocking" );
2520
+ fiber_initialize_keywords [1 ] = rb_intern_const ("pool" );
2521
+
2445
2522
char * fiber_shared_fiber_pool_free_stacks = getenv ("RUBY_SHARED_FIBER_POOL_FREE_STACKS" );
2446
2523
if (fiber_shared_fiber_pool_free_stacks ) {
2447
2524
shared_fiber_pool .free_stacks = atoi (fiber_shared_fiber_pool_free_stacks );
@@ -2452,11 +2529,14 @@ Init_Cont(void)
2452
2529
rb_eFiberError = rb_define_class ("FiberError" , rb_eStandardError );
2453
2530
rb_define_singleton_method (rb_cFiber , "yield" , rb_fiber_s_yield , -1 );
2454
2531
rb_define_method (rb_cFiber , "initialize" , rb_fiber_initialize , -1 );
2532
+ rb_define_method (rb_cFiber , "blocking?" , rb_fiber_blocking_p , 0 );
2455
2533
rb_define_method (rb_cFiber , "resume" , rb_fiber_m_resume , -1 );
2456
2534
rb_define_method (rb_cFiber , "raise" , rb_fiber_raise , -1 );
2457
2535
rb_define_method (rb_cFiber , "to_s" , fiber_to_s , 0 );
2458
2536
rb_define_alias (rb_cFiber , "inspect" , "to_s" );
2459
2537
2538
+ rb_define_global_function ("Fiber" , rb_f_fiber , -1 );
2539
+
2460
2540
#ifdef RB_EXPERIMENTAL_FIBER_POOL
2461
2541
rb_cFiberPool = rb_define_class ("Pool" , rb_cFiber );
2462
2542
rb_define_alloc_func (rb_cFiberPool , fiber_pool_alloc );
0 commit comments