Class: Libuv::Loop

Inherits:
Object
  • Object
show all
Extended by:
ClassMethods
Includes:
Assertions, Resource
Defined in:
lib/libuv/loop.rb

Defined Under Namespace

Modules: ClassMethods

Constant Summary

Constants included from Assertions

Assertions::MSG_NO_PROC

Instance Method Summary collapse

Methods included from ClassMethods

create, default, new

Methods included from Resource

#check_result, #check_result!, #resolve, #to_ptr

Methods included from Assertions

#assert_block, #assert_boolean, #assert_type

Constructor Details

#initialize(pointer) ⇒ Loop

Initialize a loop using an FFI::Pointer to a libuv loop



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/libuv/loop.rb', line 34

def initialize(pointer) # :notnew:
    @pointer = pointer
    @loop = self

    # Create an async call for scheduling work from other threads
    @run_queue = Queue.new
    @queue_proc = proc do
        # ensure we only execute what was required for this tick
        length = @run_queue.length
        length.times do
            begin
                run = @run_queue.pop true  # pop non-block
                run.call
            rescue Exception => e
                @loop.log :error, :next_tick_cb, e
            end
        end
    end
    @process_queue = Async.new(@loop, @queue_proc)

    # Create a next tick timer
    @next_tick = @loop.timer do
        @next_tick_scheduled = false
        @queue_proc.call
    end

    # Create an async call for ending the loop
    @stop_loop = Async.new @loop do
        @process_queue.close
        @stop_loop.close
        @next_tick.close

        ::Libuv::Ext.stop(@pointer)
    end
end

Instance Method Details

#all(*promises) ⇒ ::Libuv::Q::Promise

Combines multiple promises into a single promise that is resolved when all of the input promises are resolved. (thread safe)

Parameters:

  • *promises (::Libuv::Q::Promise) —

    a number of promises that will be combined into a single promise

Returns:

  • (::Libuv::Q::Promise) —

    Returns a single promise that will be resolved with an array of values, each value corresponding to the promise at the same index in the promises array. If any of the promises is resolved with a rejection, this resulting promise will be resolved with the same rejection.



109
110
111
# File 'lib/libuv/loop.rb', line 109

def all(*promises)
    Q.all(@loop, *promises)
end

#any(*promises) ⇒ ::Libuv::Q::Promise

Combines multiple promises into a single promise that is resolved when any of the input promises are resolved.

Parameters:

  • *promises (::Libuv::Q::Promise) —

    a number of promises that will be combined into a single promise

Returns:



119
120
121
# File 'lib/libuv/loop.rb', line 119

def any(*promises)
    Q.any(@loop, *promises)
end

#async(callback = nil, &block) ⇒ ::Libuv::Async

Get a new Async handle

Returns:



229
230
231
232
233
234
# File 'lib/libuv/loop.rb', line 229

def async(callback = nil, &block)
    callback ||= block
    handle = Async.new(@loop)
    handle.progress callback if callback
    handle
end

#check ⇒ ::Libuv::Check

Get a new Check handle

Returns:



214
215
216
# File 'lib/libuv/loop.rb', line 214

def check
    Check.new(@loop)
end

#defer ⇒ ::Libuv::Q::Deferred

Creates a deferred result object for where the result of an operation may only be returned at some point in the future or is being processed on a different thread (thread safe)



97
98
99
# File 'lib/libuv/loop.rb', line 97

def defer
    Q.defer(@loop)
end

#file(path, flags = 0, mode = 0) ⇒ ::Libuv::File

Opens a file and returns an object that can be used to manipulate it

Parameters:

  • path (String) —

    the path to the file or folder for watching

  • flags (Integer) (defaults to: 0) —

    see ruby File::Constants

  • mode (Integer) (defaults to: 0)

Returns:



274
275
276
277
278
279
# File 'lib/libuv/loop.rb', line 274

def file(path, flags = 0, mode = 0)
    assert_type(String, path, "path must be a String")
    assert_type(Integer, flags, "flags must be an Integer")
    assert_type(Integer, mode, "mode must be an Integer")
    File.new(@loop, path, flags, mode)
end

#filesystem ⇒ ::Libuv::Filesystem

Returns an object for manipulating the filesystem

Returns:



284
285
286
# File 'lib/libuv/loop.rb', line 284

def filesystem
    Filesystem.new(@loop)
end

#finally(*promises) ⇒ ::Libuv::Q::Promise

Combines multiple promises into a single promise that is resolved when all of the input promises are resolved or rejected.

Parameters:

  • *promises (::Libuv::Q::Promise) —

    a number of promises that will be combined into a single promise

Returns:

  • (::Libuv::Q::Promise) —

    Returns a single promise that will be resolved with an array of values, each [result, wasResolved] value pair corresponding to a at the same index in the promises array.



130
131
132
# File 'lib/libuv/loop.rb', line 130

def finally(*promises)
    Q.finally(@loop, *promises)
end

#fs_event(path) ⇒ ::Libuv::FSEvent

Get a new FSEvent instance

Parameters:

  • path (String) —

    the path to the file or folder for watching

Returns:

Raises:

  • (ArgumentError) —

    if path is not a string



263
264
265
266
# File 'lib/libuv/loop.rb', line 263

def fs_event(path)
    assert_type(String, path)
    FSEvent.new(@loop, path)
end

#handle ⇒ Object



70
# File 'lib/libuv/loop.rb', line 70

def handle; @pointer; end

#idle(callback = nil, &block) ⇒ ::Libuv::Idle

Get a new Idle handle

Parameters:

  • callback (Proc) (defaults to: nil) —

    the callback to be called on idle trigger

Returns:



222
223
224
# File 'lib/libuv/loop.rb', line 222

def idle(callback = nil, &block)
    Idle.new(@loop, callback || block)
end

#log(level, id, *args) ⇒ Object

Notifies the loop there was an event that should be logged

Parameters:

  • level (Symbol) —

    the error level (info, warn, error etc)

  • id (Object) —

    some kind of identifying information

  • *args (*args) —

    any additional information



329
330
331
# File 'lib/libuv/loop.rb', line 329

def log(level, id, *args)
    @loop_notify.notify(level, id, *args)
end

#lookup_error(err) ⇒ ::Libuv::Error

Lookup an error code and return is as an error object

Parameters:

  • err (Integer) —

    The error code to look up.

Returns:



153
154
155
156
157
158
159
160
161
# File 'lib/libuv/loop.rb', line 153

def lookup_error(err)
    name = ::Libuv::Ext.err_name(err)
    msg  = ::Libuv::Ext.strerror(err)

    ::Libuv::Error.const_get(name.to_sym).new(msg)
rescue Exception => e
    @loop.log :warn, :error_lookup_failed, e
    ::Libuv::Error::UNKNOWN.new("error lookup failed for code #{err} #{name} #{msg}")
end

#next_tick(callback = nil, &block) ⇒ Object

Queue some work to be processed in the next iteration of the event loop (thread safe)

Parameters:

  • callback (Proc) (defaults to: nil) —

    the callback to be called on the reactor thread

Raises:

  • (ArgumentError) —

    if block is not given



308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
# File 'lib/libuv/loop.rb', line 308

def next_tick(callback = nil, &block)
    callback ||= block
    assert_block(callback)

    @run_queue << callback
    if @reactor_thread == Thread.current
        # Create a next tick timer
        if not @next_tick_scheduled
            @next_tick.start(0)
            @next_tick_scheduled = true
        end
    else
        @process_queue.call
    end
end

#now ⇒ Fixnum

Get current time in microseconds

Returns:

  • (Fixnum)


145
146
147
# File 'lib/libuv/loop.rb', line 145

def now
    ::Libuv::Ext.now(@pointer)
end

#pipe(ipc = false) ⇒ ::Libuv::Pipe

Get a new Pipe instance

Parameters:

  • ipc (true, false) (defaults to: false) —

    indicate if a handle will be used for ipc, useful for sharing tcp socket between processes

Returns:



192
193
194
# File 'lib/libuv/loop.rb', line 192

def pipe(ipc = false)
    Pipe.new(@loop, ipc)
end

#prepare ⇒ ::Libuv::Prepare

Get a new Prepare handle

Returns:



207
208
209
# File 'lib/libuv/loop.rb', line 207

def prepare
    Prepare.new(@loop)
end

#run(run_type = :UV_RUN_DEFAULT) {|promise| ... } ⇒ Object

Run the actual event loop. This method will block until the loop is stopped.

Parameters:

  • run_type (:UV_RUN_DEFAULT, :UV_RUN_ONCE, :UV_RUN_NOWAIT) (defaults to: :UV_RUN_DEFAULT)

Yield Parameters:

  • promise (::Libuv::Q::Promise) —

    Yields a promise that can be used for logging unhandled exceptions on the loop.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/libuv/loop.rb', line 77

def run(run_type = :UV_RUN_DEFAULT)
    @loop_notify = @loop.defer

    begin
        @reactor_thread = Thread.current
        yield  @loop_notify.promise if block_given?
        ::Libuv::Ext.run(@pointer, run_type)  # This is blocking
    ensure
        @reactor_thread = nil
        @run_queue.clear
    end

    @loop
end

#schedule(callback = nil, &block) ⇒ Object

Schedule some work to be processed on the event loop as soon as possible (thread safe)

Parameters:

  • callback (Proc) (defaults to: nil) —

    the callback to be called on the reactor thread

Raises:

  • (ArgumentError) —

    if block is not given



292
293
294
295
296
297
298
299
300
301
302
# File 'lib/libuv/loop.rb', line 292

def schedule(callback = nil, &block)
    callback ||= block
    assert_block(callback)

    if @reactor_thread == Thread.current
        block.call
    else
        @run_queue << callback
        @process_queue.call
    end
end

#signal(signum = nil, callback = nil, &block) ⇒ ::Libuv::Signal

Get a new signal handler

Returns:



239
240
241
242
243
244
245
# File 'lib/libuv/loop.rb', line 239

def signal(signum = nil, callback = nil, &block)
    callback ||= block
    handle = Signal.new(@loop)
    handle.progress callback if callback
    handle.start(signum) if signum
    handle
end

#stop ⇒ Object

Closes handles opened by the loop class and completes the current loop iteration (thread safe)



334
335
336
# File 'lib/libuv/loop.rb', line 334

def stop
    @stop_loop.call
end

#tcp ⇒ ::Libuv::TCP

Get a new TCP instance

Returns:



166
167
168
# File 'lib/libuv/loop.rb', line 166

def tcp
    TCP.new(@loop)
end

#timer(callback = nil, &blk) ⇒ ::Libuv::Timer

Get a new timer instance

Parameters:

  • callback (Proc) (defaults to: nil) —

    the callback to be called on timer trigger

Returns:



200
201
202
# File 'lib/libuv/loop.rb', line 200

def timer(callback = nil, &blk)
    Timer.new(@loop, callback || blk)
end

#tty(fileno, readable = false) ⇒ ::Libuv::TTY

Get a new TTY instance

Parameters:

  • fileno (Integer) —

    Integer file descriptor of a tty device

  • readable (true, false) (defaults to: false) —

    Boolean indicating if TTY is readable

Returns:



182
183
184
185
186
# File 'lib/libuv/loop.rb', line 182

def tty(fileno, readable = false)
    assert_type(Integer, fileno, "io#fileno must return an integer file descriptor, #{fileno.inspect} given")

    TTY.new(@loop, fileno, readable)
end

#udp ⇒ ::Libuv::UDP

Get a new UDP instance

Returns:



173
174
175
# File 'lib/libuv/loop.rb', line 173

def udp
    UDP.new(@loop)
end

#update_time ⇒ Object

forces loop time update, useful for getting more granular times

Returns:

  • nil



138
139
140
# File 'lib/libuv/loop.rb', line 138

def update_time
    ::Libuv::Ext.update_time(@pointer)
end

#work(callback = nil, &block) ⇒ ::Libuv::Work

Queue some work for processing in the libuv thread pool

Parameters:

  • callback (Proc) (defaults to: nil) —

    the callback to be called in the thread pool

Returns:

Raises:

  • (ArgumentError) —

    if block is not given



252
253
254
255
256
# File 'lib/libuv/loop.rb', line 252

def work(callback = nil, &block)
    callback ||= block
    assert_block(callback)
    Work.new(@loop, callback)    # Work is a promise object
end