File: loop.rb

package info (click to toggle)
ruby-cool.io 1.9.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 716 kB
  • sloc: ansic: 6,851; ruby: 1,730; makefile: 6
file content (122 lines) | stat: -rw-r--r-- 3,404 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#--
# Copyright (C)2007-10 Tony Arcieri
# You can redistribute this under the terms of the Ruby license
# See file LICENSE for details
#++

require 'thread'

# Monkeypatch Thread to include a method for obtaining the default Coolio::Loop
class Thread
  def _coolio_loop
    @_coolio_loop ||= Coolio::Loop.new
  end
end

module Coolio
  class Loop
    # Retrieve the default event loop for the current thread
    def self.default
      Thread.current._coolio_loop
    end

    # Create a new Coolio::Loop
    #
    # Options:
    #
    # :skip_environment (boolean)
    #   Ignore the $LIBEV_FLAGS environment variable
    #
    # :fork_check (boolean)
    #   Enable autodetection of forks
    #
    # :backend
    #   Choose the default backend, one (or many in an array) of:
    #     :select (most platforms)
    #     :poll   (most platforms except Windows)
    #     :epoll  (Linux)
    #     :kqueue (BSD/Mac OS X)
    #     :port   (Solaris 10)
    #
    def initialize(options = {})
      @watchers = {}
      @active_watchers = 0

      flags = 0

      options.each do |option, value|
        case option
        when :skip_environment
          flags |= EVFLAG_NOEV if value
        when :fork_check
          flags |= EVFLAG_FORKCHECK if value
        when :backend
          value = [value] unless value.is_a? Array
          value.each do |backend|
            case backend
            when :select then flags |= EVBACKEND_SELECT
            when :poll   then flags |= EVBACKEND_POLL
            when :epoll  then flags |= EVBACKEND_EPOLL
            when :kqueue then flags |= EVBACKEND_KQUEUE
            when :port   then flags |= EVBACKEND_PORT
            else raise ArgumentError, "no such backend: #{backend}"
            end
          end
        else raise ArgumentError, "no such option: #{option}"
        end
      end

      @loop = ev_loop_new(flags)
    end

    # Attach a watcher to the loop
    def attach(watcher)
      watcher.attach self
    end

    # Run the event loop and dispatch events back to Ruby.  If there
    # are no watchers associated with the event loop it will return
    # immediately.  Otherwise, run will continue blocking and making
    # event callbacks to watchers until all watchers associated with
    # the loop have been disabled or detached.  The loop may be
    # explicitly stopped by calling the stop method on the loop object.
    def run(timeout = nil)
      raise RuntimeError, "no watchers for this loop" if @watchers.empty?

      @running = true
      while @running and not @active_watchers.zero?
        run_once(timeout)
      end
      @running = false
    end

    # Stop the event loop if it's running
    def stop
      raise RuntimeError, "loop not running" unless @running
      @running = false
    end

    # Does the loop have any active watchers?
    def has_active_watchers?
      @active_watchers > 0
    end

    # All watchers attached to the current loop
    def watchers
      @watchers.keys
    end

    #######
    private
    #######

    EVFLAG_NOENV     = 0x1000000  # do NOT consult environment
    EVFLAG_FORKCHECK = 0x2000000  # check for a fork in each iteration

    EVBACKEND_SELECT = 0x00000001 # supported about anywhere
    EVBACKEND_POLL   = 0x00000002 # !win
    EVBACKEND_EPOLL  = 0x00000004 # linux
    EVBACKEND_KQUEUE = 0x00000008 # bsd
    EVBACKEND_PORT   = 0x00000020 # solaris 10
  end
end