@@ -49,6 +49,8 @@ function eof(s::AsyncStream)
49
49
! isopen (s) && nb_available (s. buffer)<= 0
50
50
end
51
51
52
+ const DEFAULT_READ_BUFFER_SZ = 10485760 # 10 MB
53
+
52
54
const StatusUninit = 0 # handle is allocated, but not initialized
53
55
const StatusInit = 1 # handle is valid, but not connected/active
54
56
const StatusConnecting = 2 # handle is in process of connecting
@@ -104,6 +106,7 @@ type Pipe <: AsyncStream
104
106
closenotify:: Condition
105
107
sendbuf:: Nullable{IOBuffer}
106
108
lock:: ReentrantLock
109
+ throttle:: Int
107
110
108
111
Pipe (handle) = new (
109
112
handle,
@@ -113,7 +116,8 @@ type Pipe <: AsyncStream
113
116
false ,Condition (),
114
117
false ,Condition (),
115
118
false ,Condition (),
116
- nothing , ReentrantLock ())
119
+ nothing , ReentrantLock (),
120
+ DEFAULT_READ_BUFFER_SZ)
117
121
end
118
122
function Pipe ()
119
123
handle = Libc. malloc (_sizeof_uv_named_pipe)
@@ -182,6 +186,7 @@ type TTY <: AsyncStream
182
186
closenotify:: Condition
183
187
sendbuf:: Nullable{IOBuffer}
184
188
lock:: ReentrantLock
189
+ throttle:: Int
185
190
@windows_only ispty:: Bool
186
191
function TTY (handle)
187
192
tty = new (
@@ -191,7 +196,8 @@ type TTY <: AsyncStream
191
196
PipeBuffer (),
192
197
false ,Condition (),
193
198
false ,Condition (),
194
- nothing , ReentrantLock ())
199
+ nothing , ReentrantLock (),
200
+ DEFAULT_READ_BUFFER_SZ)
195
201
@windows_only tty. ispty = ccall (:jl_ispty , Cint, (Ptr{Void},), handle)!= 0
196
202
tty
197
203
end
@@ -269,7 +275,7 @@ function init_stdio(handle)
269
275
end
270
276
end
271
277
272
- function stream_wait (x,c... )
278
+ function stream_wait (x, c... ) # for x::LibuvObject
273
279
preserve_handle (x)
274
280
try
275
281
return wait (c... )
@@ -307,26 +313,51 @@ end
307
313
function wait_connected (x)
308
314
check_open (x)
309
315
while x. status == StatusConnecting
310
- stream_wait (x,x. connectnotify)
316
+ stream_wait (x, x. connectnotify)
311
317
check_open (x)
312
318
end
313
319
end
314
320
315
321
function wait_readbyte (x:: AsyncStream , c:: UInt8 )
316
- while isopen (x) && search (x. buffer,c) <= 0
317
- start_reading (x)
318
- stream_wait (x,x. readnotify)
322
+ preserve_handle (x)
323
+ try
324
+ while isopen (x) && search (x. buffer,c) <= 0
325
+ start_reading (x) # ensure we are reading
326
+ wait (x. readnotify)
327
+ end
328
+ finally
329
+ if isempty (x. readnotify. waitq)
330
+ stop_reading (x) # stop reading iff there are currently no other read clients of the stream
331
+ end
332
+ unpreserve_handle (x)
319
333
end
320
334
end
321
335
322
336
function wait_readnb (x:: AsyncStream , nb:: Int )
323
- while isopen (x) && nb_available (x. buffer) < nb
324
- start_reading (x)
325
- stream_wait (x,x. readnotify)
337
+ oldthrottle = x. throttle
338
+ preserve_handle (x)
339
+ try
340
+ while isopen (x) && nb_available (x. buffer) < nb
341
+ x. throttle = max (nb, x. throttle)
342
+ start_reading (x) # ensure we are reading
343
+ wait (x. readnotify)
344
+ end
345
+ finally
346
+ if oldthrottle <= x. throttle <= nb
347
+ x. throttle = oldthrottle
348
+ end
349
+ if isempty (x. readnotify. waitq)
350
+ stop_reading (x) # stop reading iff there are currently no other read clients of the stream
351
+ end
352
+ unpreserve_handle (x)
326
353
end
327
354
end
328
355
329
- wait_close (x) = if isopen (x) stream_wait (x,x. closenotify); end
356
+ function wait_close (x:: AsyncStream )
357
+ if isopen (x)
358
+ stream_wait (x, x. closenotify)
359
+ end
360
+ end
330
361
331
362
# from `connect`
332
363
function _uv_hook_connectcb (sock:: AsyncStream , status:: Int32 )
@@ -367,8 +398,7 @@ function alloc_request(buffer::IOBuffer, recommended_size::UInt)
367
398
end
368
399
function _uv_hook_alloc_buf (stream:: AsyncStream , recommended_size:: UInt )
369
400
(buf,size) = alloc_request (stream. buffer, recommended_size)
370
- @assert size> 0 # because libuv requires this (TODO : possibly stop reading too if it fails)
371
- (buf,UInt (size))
401
+ return (buf,UInt (size))
372
402
end
373
403
374
404
function notify_filled (buffer:: IOBuffer , nread:: Int , base:: Ptr{Void} , len:: UInt )
@@ -394,36 +424,39 @@ function notify_filled(stream::AsyncStream, nread::Int)
394
424
end
395
425
end
396
426
397
- const READ_BUFFER_SZ= 10485760 # 10 MB
398
427
function _uv_hook_readcb (stream:: AsyncStream , nread:: Int , base:: Ptr{Void} , len:: UInt )
399
428
if nread < 0
400
- if nread != UV_EOF
401
- # This is a fatal connectin error. Shutdown requests as per the usual
402
- # close function won't work and libuv will fail with an assertion failure
403
- ccall (:jl_forceclose_uv ,Void,(Ptr{Void},),stream. handle)
404
- notify_error (stream. readnotify, UVError (" readcb" ,nread))
405
- else
429
+ if nread == UV_ENOBUFS && len == 0
430
+ # remind the client that stream.buffer is full
431
+ notify (stream. readnotify)
432
+ elseif nread == UV_EOF
406
433
if isa (stream,TTY)
407
- stream. status = StatusEOF
434
+ stream. status = StatusEOF # libuv called stop_reading already
408
435
notify (stream. readnotify)
409
436
notify (stream. closenotify)
410
437
else
411
438
close (stream)
412
439
end
440
+ else
441
+ # This is a fatal connection error. Shutdown requests as per the usual
442
+ # close function won't work and libuv will fail with an assertion failure
443
+ ccall (:jl_forceclose_uv ,Void,(Ptr{Void},),stream. handle)
444
+ notify_error (stream. readnotify, UVError (" readcb" ,nread))
413
445
end
414
446
else
415
447
notify_filled (stream. buffer, nread, base, len)
416
448
notify_filled (stream, nread)
417
449
notify (stream. readnotify)
418
450
end
419
451
420
- # Stop reading when
421
- # 1) when we have an infinite buffer, and we have accumulated a lot of unread data OR
452
+ # Stop background reading when
453
+ # 1) we have accumulated a lot of unread data OR
422
454
# 2) we have an alternate buffer that has reached its limit.
423
- if (is_maxsize_unlimited (stream . buffer) && ( nb_available (stream. buffer) > READ_BUFFER_SZ ) ) ||
424
- (nb_available (stream. buffer) = = stream. buffer. maxsize)
455
+ if (nb_available (stream. buffer) >= stream . throttle ) ||
456
+ (nb_available (stream. buffer) > = stream. buffer. maxsize)
425
457
stop_reading (stream)
426
458
end
459
+ nothing
427
460
end
428
461
429
462
reseteof (x:: IO ) = nothing
@@ -532,7 +565,7 @@ function sleep(sec::Real)
532
565
end )
533
566
start_timer (timer, float (sec), 0 )
534
567
try
535
- stream_wait (timer,w)
568
+ stream_wait (timer, w)
536
569
finally
537
570
stop_timer (timer)
538
571
end
@@ -640,15 +673,15 @@ function start_reading(stream::AsyncStream)
640
673
end
641
674
end
642
675
function start_reading (stream:: AsyncStream , cb:: Function )
643
- start_reading (stream)
676
+ failure = start_reading (stream)
644
677
stream. readcb = cb
645
678
nread = nb_available (stream. buffer)
646
679
if nread > 0
647
680
notify_filled (stream, nread)
648
681
end
649
- nothing
682
+ return failure_code
650
683
end
651
- start_reading (stream:: AsyncStream , cb:: Bool ) = (start_reading (stream); stream. readcb = cb; nothing )
684
+ start_reading (stream:: AsyncStream , cb:: Bool ) = (failure_code = start_reading (stream); stream. readcb = cb; return failure_code )
652
685
653
686
function stop_reading (stream:: AsyncStream )
654
687
if stream. status == StatusActive
@@ -662,10 +695,9 @@ function stop_reading(stream::AsyncStream)
662
695
end
663
696
end
664
697
665
- function readall (stream:: AsyncStream )
666
- start_reading (stream)
667
- wait_close (stream)
668
- return takebuf_string (stream. buffer)
698
+ function readbytes (stream:: AsyncStream )
699
+ wait_readnb (stream, typemax (Int))
700
+ return takebuf_array (stream. buffer)
669
701
end
670
702
671
703
function read! {T} (s:: AsyncStream , a:: Array{T} )
@@ -687,16 +719,22 @@ function read!(s::AsyncStream, a::Vector{UInt8})
687
719
end
688
720
689
721
if nb <= SZ_UNBUFFERED_IO # Under this limit we are OK with copying the array from the stream's buffer
690
- wait_readnb (s,nb)
722
+ wait_readnb (s, nb)
691
723
read! (sbuf, a)
692
724
else
693
- stop_reading (s) # Just playing it safe, since we are going to switch buffers.
694
- newbuf = PipeBuffer (a, nb)
695
- newbuf. size = 0
696
- s. buffer = newbuf
697
- write (newbuf, sbuf)
698
- wait_readnb (s,nb)
699
- s. buffer = sbuf
725
+ try
726
+ stop_reading (s) # Just playing it safe, since we are going to switch buffers.
727
+ newbuf = PipeBuffer (a, #= maxsize=# nb)
728
+ newbuf. size = 0 # reset the write pointer to the beginning
729
+ s. buffer = newbuf
730
+ write (newbuf, sbuf)
731
+ wait_readnb (s, nb)
732
+ finally
733
+ s. buffer = sbuf
734
+ if ! isempty (s. readnotify. waitq)
735
+ start_reading (x) # resume reading iff there are currently other read clients of the stream
736
+ end
737
+ end
700
738
end
701
739
return a
702
740
end
711
749
function read (this:: AsyncStream ,:: Type{UInt8} )
712
750
buf = this. buffer
713
751
@assert buf. seekable == false
714
- wait_readnb (this,1 )
715
- read (buf,UInt8)
752
+ wait_readnb (this, 1 )
753
+ read (buf, UInt8)
716
754
end
717
755
718
756
readline (this:: AsyncStream ) = readuntil (this, ' \n ' )
@@ -776,11 +814,11 @@ function buffer_or_write(s::AsyncStream, p::Ptr, n::Integer)
776
814
end
777
815
778
816
totb = nb_available (buf) + n
779
- if totb < maxsize ( buf)
817
+ if totb < buf. maxsize
780
818
nb = write (buf, p, n)
781
819
else
782
820
flush (s)
783
- if n > maxsize ( buf)
821
+ if n > buf. maxsize
784
822
nb = uv_write (s, p, n)
785
823
else
786
824
nb = write (buf, p, n)
@@ -988,19 +1026,10 @@ function wait_readnb(s::BufferStream, nb::Int)
988
1026
while isopen (s) && nb_available (s. buffer) < nb
989
1027
wait (s. r_c)
990
1028
end
991
-
992
- (nb_available (s. buffer) < nb) && error (" closed BufferStream" )
993
- end
994
-
995
- function eof (s:: BufferStream )
996
- wait_readnb (s,1 )
997
- ! isopen (s) && nb_available (s. buffer)<= 0
998
1029
end
999
1030
1000
1031
show (io:: IO , s:: BufferStream ) = print (io," BufferStream() bytes waiting:" ,nb_available (s. buffer)," , isopen:" , s. is_open)
1001
1032
1002
- nb_available (s:: BufferStream ) = nb_available (s. buffer)
1003
-
1004
1033
function wait_readbyte (s:: BufferStream , c:: UInt8 )
1005
1034
while isopen (s) && search (s. buffer,c) <= 0
1006
1035
wait (s. r_c)
0 commit comments