@@ -16,8 +16,9 @@ mutable struct IOStream <: IO
16
16
name:: AbstractString
17
17
mark:: Int64
18
18
lock:: ReentrantLock
19
+ _dolock:: Bool
19
20
20
- IOStream (name:: AbstractString , buf:: Array{UInt8,1} ) = new (pointer (buf), buf, name, - 1 , ReentrantLock ())
21
+ IOStream (name:: AbstractString , buf:: Array{UInt8,1} ) = new (pointer (buf), buf, name, - 1 , ReentrantLock (), true )
21
22
end
22
23
23
24
function IOStream (name:: AbstractString , finalize:: Bool )
@@ -33,6 +34,18 @@ IOStream(name::AbstractString) = IOStream(name, true)
33
34
unsafe_convert (T:: Type{Ptr{Cvoid}} , s:: IOStream ) = convert (T, pointer (s. ios))
34
35
show (io:: IO , s:: IOStream ) = print (io, " IOStream(" , s. name, " )" )
35
36
37
+ macro _lock_ios (s, expr)
38
+ s = esc (s)
39
+ quote
40
+ l = ($ s). _dolock
41
+ temp = ($ s). lock
42
+ l && lock (temp)
43
+ val = $ (esc (expr))
44
+ l && unlock (temp)
45
+ val
46
+ end
47
+ end
48
+
36
49
"""
37
50
fd(stream)
38
51
@@ -46,13 +59,13 @@ stat(s::IOStream) = stat(fd(s))
46
59
isopen (s:: IOStream ) = ccall (:ios_isopen , Cint, (Ptr{Cvoid},), s. ios) != 0
47
60
48
61
function close (s:: IOStream )
49
- bad = @lock_nofail s . lock ccall (:ios_close , Cint, (Ptr{Cvoid},), s. ios) != 0
62
+ bad = @_lock_ios s ccall (:ios_close , Cint, (Ptr{Cvoid},), s. ios) != 0
50
63
systemerror (" close" , bad)
51
64
end
52
65
53
66
function flush (s:: IOStream )
54
67
sigatomic_begin ()
55
- bad = @lock_nofail s . lock ccall (:ios_flush , Cint, (Ptr{Cvoid},), s. ios) != 0
68
+ bad = @_lock_ios s ccall (:ios_flush , Cint, (Ptr{Cvoid},), s. ios) != 0
56
69
sigatomic_end ()
57
70
systemerror (" flush" , bad)
58
71
end
@@ -91,7 +104,7 @@ julia> String(take!(io))
91
104
```
92
105
"""
93
106
function truncate (s:: IOStream , n:: Integer )
94
- err = @lock_nofail s . lock ccall (:ios_trunc , Cint, (Ptr{Cvoid}, Csize_t), s. ios, n) != 0
107
+ err = @_lock_ios s ccall (:ios_trunc , Cint, (Ptr{Cvoid}, Csize_t), s. ios, n) != 0
95
108
systemerror (" truncate" , err)
96
109
return s
97
110
end
@@ -112,7 +125,7 @@ julia> read(io, Char)
112
125
```
113
126
"""
114
127
function seek (s:: IOStream , n:: Integer )
115
- ret = @lock_nofail s . lock ccall (:ios_seek , Int64, (Ptr{Cvoid}, Int64), s. ios, n)
128
+ ret = @_lock_ios s ccall (:ios_seek , Int64, (Ptr{Cvoid}, Int64), s. ios, n)
116
129
systemerror (" seek" , ret == - 1 )
117
130
ret < - 1 && error (" seek failed" )
118
131
return s
@@ -146,7 +159,7 @@ seekstart(s::IO) = seek(s,0)
146
159
Seek a stream to its end.
147
160
"""
148
161
function seekend (s:: IOStream )
149
- err = @lock_nofail s . lock ccall (:ios_seek_end , Int64, (Ptr{Cvoid},), s. ios) != 0
162
+ err = @_lock_ios s ccall (:ios_seek_end , Int64, (Ptr{Cvoid},), s. ios) != 0
150
163
systemerror (" seekend" , err)
151
164
return s
152
165
end
@@ -169,7 +182,7 @@ julia> read(io, Char)
169
182
```
170
183
"""
171
184
function skip (s:: IOStream , delta:: Integer )
172
- ret = @lock_nofail s . lock ccall (:ios_skip , Int64, (Ptr{Cvoid}, Int64), s. ios, delta)
185
+ ret = @_lock_ios s ccall (:ios_skip , Int64, (Ptr{Cvoid}, Int64), s. ios, delta)
173
186
systemerror (" skip" , ret == - 1 )
174
187
ret < - 1 && error (" skip failed" )
175
188
return s
@@ -201,13 +214,13 @@ julia> position(io)
201
214
```
202
215
"""
203
216
function position (s:: IOStream )
204
- pos = @lock_nofail s . lock ccall (:ios_pos , Int64, (Ptr{Cvoid},), s. ios)
217
+ pos = @_lock_ios s ccall (:ios_pos , Int64, (Ptr{Cvoid},), s. ios)
205
218
systemerror (" position" , pos == - 1 )
206
219
return pos
207
220
end
208
221
209
222
_eof_nolock (s:: IOStream ) = ccall (:ios_eof_blocking , Cint, (Ptr{Cvoid},), s. ios) != 0
210
- eof (s:: IOStream ) = @lock_nofail s . lock _eof_nolock (s)
223
+ eof (s:: IOStream ) = @_lock_ios s _eof_nolock (s)
211
224
212
225
# # constructing and opening streams ##
213
226
229
242
fdio (fd:: Integer , own:: Bool = false ) = fdio (string (" <fd " ,fd," >" ), fd, own)
230
243
231
244
"""
232
- open(filename::AbstractString; keywords...) -> IOStream
245
+ open(filename::AbstractString; lock = true, keywords...) -> IOStream
233
246
234
247
Open a file in a mode specified by five boolean keyword arguments:
235
248
@@ -243,8 +256,14 @@ Open a file in a mode specified by five boolean keyword arguments:
243
256
244
257
The default when no keywords are passed is to open files for reading only.
245
258
Returns a stream for accessing the opened file.
259
+
260
+ The `lock` keyword argument controls whether operations will be locked for
261
+ safe multi-threaded access.
262
+
263
+ !!! compat "Julia 1.5"
264
+ The `lock` argument is available as of Julia 1.5.
246
265
"""
247
- function open (fname:: AbstractString ;
266
+ function open (fname:: AbstractString ; lock = true ,
248
267
read :: Union{Bool,Nothing} = nothing ,
249
268
write :: Union{Bool,Nothing} = nothing ,
250
269
create :: Union{Bool,Nothing} = nothing ,
@@ -259,6 +278,9 @@ function open(fname::AbstractString;
259
278
append = append,
260
279
)
261
280
s = IOStream (string (" <file " ,fname," >" ))
281
+ if ! lock
282
+ s. _dolock = false
283
+ end
262
284
systemerror (" opening file $(repr (fname)) " ,
263
285
ccall (:ios_file , Ptr{Cvoid},
264
286
(Ptr{UInt8}, Cstring, Cint, Cint, Cint, Cint),
@@ -270,7 +292,7 @@ function open(fname::AbstractString;
270
292
end
271
293
272
294
"""
273
- open(filename::AbstractString, [mode::AbstractString]) -> IOStream
295
+ open(filename::AbstractString, [mode::AbstractString]; lock = true ) -> IOStream
274
296
275
297
Alternate syntax for open, where a string-based mode specifier is used instead of the five
276
298
booleans. The values of `mode` correspond to those from `fopen(3)` or Perl `open`, and are
@@ -285,6 +307,9 @@ equivalent to setting the following boolean groups:
285
307
| `w+` | read, write, create, truncate | `truncate = true, read = true` |
286
308
| `a+` | read, write, create, append | `append = true, read = true` |
287
309
310
+ The `lock` keyword argument controls whether operations will be locked for
311
+ safe multi-threaded access.
312
+
288
313
# Examples
289
314
```jldoctest
290
315
julia> io = open("myfile.txt", "w");
@@ -313,31 +338,34 @@ julia> close(io)
313
338
314
339
julia> rm("myfile.txt")
315
340
```
341
+
342
+ !!! compat "Julia 1.5"
343
+ The `lock` argument is available as of Julia 1.5.
316
344
"""
317
- function open (fname:: AbstractString , mode:: AbstractString )
318
- mode == " r" ? open (fname, read = true ) :
319
- mode == " r+" ? open (fname, read = true , write = true ) :
320
- mode == " w" ? open (fname, truncate = true ) :
321
- mode == " w+" ? open (fname, truncate = true , read = true ) :
322
- mode == " a" ? open (fname, append = true ) :
323
- mode == " a+" ? open (fname, append = true , read = true ) :
345
+ function open (fname:: AbstractString , mode:: AbstractString ; lock = true )
346
+ mode == " r" ? open (fname, lock = lock, read = true ) :
347
+ mode == " r+" ? open (fname, lock = lock, read = true , write = true ) :
348
+ mode == " w" ? open (fname, lock = lock, truncate = true ) :
349
+ mode == " w+" ? open (fname, lock = lock, truncate = true , read = true ) :
350
+ mode == " a" ? open (fname, lock = lock, append = true ) :
351
+ mode == " a+" ? open (fname, lock = lock, append = true , read = true ) :
324
352
throw (ArgumentError (" invalid open mode: $mode " ))
325
353
end
326
354
327
355
# # low-level calls ##
328
356
329
357
function write (s:: IOStream , b:: UInt8 )
330
358
iswritable (s) || throw (ArgumentError (" write failed, IOStream is not writeable" ))
331
- Int (@lock_nofail s . lock ccall (:ios_putc , Cint, (Cint, Ptr{Cvoid}), b, s. ios))
359
+ Int (@_lock_ios s ccall (:ios_putc , Cint, (Cint, Ptr{Cvoid}), b, s. ios))
332
360
end
333
361
334
362
function unsafe_write (s:: IOStream , p:: Ptr{UInt8} , nb:: UInt )
335
363
iswritable (s) || throw (ArgumentError (" write failed, IOStream is not writeable" ))
336
- return Int (@lock_nofail s . lock ccall (:ios_write , Csize_t, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), s. ios, p, nb))
364
+ return Int (@_lock_ios s ccall (:ios_write , Csize_t, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), s. ios, p, nb))
337
365
end
338
366
339
367
# num bytes available without blocking
340
- bytesavailable (s:: IOStream ) = @lock_nofail s . lock ccall (:jl_nb_available , Int32, (Ptr{Cvoid},), s. ios)
368
+ bytesavailable (s:: IOStream ) = @_lock_ios s ccall (:jl_nb_available , Int32, (Ptr{Cvoid},), s. ios)
341
369
342
370
function readavailable (s:: IOStream )
343
371
lock (s. lock)
@@ -353,7 +381,7 @@ function readavailable(s::IOStream)
353
381
end
354
382
355
383
function read (s:: IOStream , :: Type{UInt8} )
356
- b = @lock_nofail s . lock ccall (:ios_getc , Cint, (Ptr{Cvoid},), s. ios)
384
+ b = @_lock_ios s ccall (:ios_getc , Cint, (Ptr{Cvoid},), s. ios)
357
385
if b == - 1
358
386
throw (EOFError ())
359
387
end
@@ -379,7 +407,7 @@ read(s::IOStream, ::Type{Float64}) = reinterpret(Float64, read(s, Int64))
379
407
end
380
408
381
409
function unsafe_read (s:: IOStream , p:: Ptr{UInt8} , nb:: UInt )
382
- nr = @lock_nofail s . lock ccall (:ios_readall , Csize_t, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), s, p, nb)
410
+ nr = @_lock_ios s ccall (:ios_readall , Csize_t, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), s, p, nb)
383
411
if nr != nb
384
412
throw (EOFError ())
385
413
end
@@ -389,25 +417,25 @@ end
389
417
# # text I/O ##
390
418
391
419
take! (s:: IOStream ) =
392
- @lock_nofail s . lock ccall (:jl_take_buffer , Vector{UInt8}, (Ptr{Cvoid},), s. ios)
420
+ @_lock_ios s ccall (:jl_take_buffer , Vector{UInt8}, (Ptr{Cvoid},), s. ios)
393
421
394
422
function readuntil (s:: IOStream , delim:: UInt8 ; keep:: Bool = false )
395
- @lock_nofail s . lock ccall (:jl_readuntil , Array{UInt8,1 }, (Ptr{Cvoid}, UInt8, UInt8, UInt8), s. ios, delim, 0 , ! keep)
423
+ @_lock_ios s ccall (:jl_readuntil , Array{UInt8,1 }, (Ptr{Cvoid}, UInt8, UInt8, UInt8), s. ios, delim, 0 , ! keep)
396
424
end
397
425
398
426
# like readuntil, above, but returns a String without requiring a copy
399
427
function readuntil_string (s:: IOStream , delim:: UInt8 , keep:: Bool )
400
- @lock_nofail s . lock ccall (:jl_readuntil , Ref{String}, (Ptr{Cvoid}, UInt8, UInt8, UInt8), s. ios, delim, 1 , ! keep)
428
+ @_lock_ios s ccall (:jl_readuntil , Ref{String}, (Ptr{Cvoid}, UInt8, UInt8, UInt8), s. ios, delim, 1 , ! keep)
401
429
end
402
430
403
431
function readline (s:: IOStream ; keep:: Bool = false )
404
- @lock_nofail s . lock ccall (:jl_readuntil , Ref{String}, (Ptr{Cvoid}, UInt8, UInt8, UInt8), s. ios, ' \n ' , 1 , keep ? 0 : 2 )
432
+ @_lock_ios s ccall (:jl_readuntil , Ref{String}, (Ptr{Cvoid}, UInt8, UInt8, UInt8), s. ios, ' \n ' , 1 , keep ? 0 : 2 )
405
433
end
406
434
407
435
function readbytes_all! (s:: IOStream , b:: Array{UInt8} , nb)
408
436
olb = lb = length (b)
409
437
nr = 0
410
- @lock_nofail s . lock begin
438
+ @_lock_ios s begin
411
439
GC. @preserve b while nr < nb
412
440
if lb < nr+ 1
413
441
lb = max (65536 , (nr+ 1 ) * 2 )
@@ -430,7 +458,7 @@ function readbytes_some!(s::IOStream, b::Array{UInt8}, nb)
430
458
resize! (b, nb)
431
459
end
432
460
local nr
433
- @lock_nofail s . lock begin
461
+ @_lock_ios s begin
434
462
nr = GC. @preserve b Int (ccall (:ios_read , Csize_t, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t),
435
463
s. ios, pointer (b), nb))
436
464
end
498
526
# # peek ##
499
527
500
528
function peek (s:: IOStream )
501
- @lock_nofail s . lock ccall (:ios_peekc , Cint, (Ptr{Cvoid},), s)
529
+ @_lock_ios s ccall (:ios_peekc , Cint, (Ptr{Cvoid},), s)
502
530
end
0 commit comments