libvirt_ffi 0.2.1 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +78 -0
  3. data/Gemfile +7 -2
  4. data/Rakefile +6 -1
  5. data/bin/console +1 -0
  6. data/exe/libvirt +1 -0
  7. data/lib/libvirt.rb +14 -13
  8. data/lib/libvirt/base_info.rb +34 -0
  9. data/lib/libvirt/connection.rb +156 -47
  10. data/lib/libvirt/domain.rb +136 -8
  11. data/lib/libvirt/domain_callback_storage.rb +69 -0
  12. data/lib/libvirt/errors.rb +65 -0
  13. data/lib/libvirt/event.rb +60 -38
  14. data/lib/libvirt/ffi.rb +17 -0
  15. data/lib/libvirt/ffi/common.rb +8 -1
  16. data/lib/libvirt/ffi/domain.rb +796 -69
  17. data/lib/libvirt/ffi/error.rb +243 -0
  18. data/lib/libvirt/ffi/event.rb +30 -36
  19. data/lib/libvirt/ffi/helpers.rb +17 -0
  20. data/lib/libvirt/ffi/host.rb +122 -0
  21. data/lib/libvirt/ffi/storage.rb +149 -0
  22. data/lib/libvirt/ffi/stream.rb +74 -0
  23. data/lib/libvirt/node_info.rb +2 -41
  24. data/lib/libvirt/storage_pool.rb +70 -0
  25. data/lib/libvirt/storage_pool_info.rb +7 -0
  26. data/lib/libvirt/storage_volume.rb +51 -0
  27. data/lib/libvirt/storage_volume_info.rb +7 -0
  28. data/lib/libvirt/stream.rb +124 -0
  29. data/lib/libvirt/util.rb +75 -8
  30. data/lib/libvirt/version.rb +1 -1
  31. data/lib/libvirt/xml.rb +23 -0
  32. data/lib/libvirt/xml/disk.rb +59 -0
  33. data/lib/libvirt/xml/domain.rb +76 -0
  34. data/lib/libvirt/xml/generic.rb +252 -0
  35. data/lib/libvirt/xml/graphics.rb +14 -0
  36. data/lib/libvirt/xml/max_vcpu.rb +12 -0
  37. data/lib/libvirt/xml/memory.rb +14 -0
  38. data/lib/libvirt/xml/storage_pool.rb +24 -0
  39. data/lib/libvirt/xml/storage_volume.rb +32 -0
  40. data/lib/libvirt/xml/vcpu.rb +12 -0
  41. data/lib/libvirt_ffi.rb +2 -0
  42. data/libvirt.gemspec +5 -1
  43. data/test_usage/support/libvirt_async.rb +33 -31
  44. data/test_usage/support/log_formatter.rb +5 -10
  45. data/test_usage/test_domain.rb +43 -0
  46. data/test_usage/test_event_loop.rb +134 -33
  47. data/test_usage/test_libvirtd_restart.rb +63 -0
  48. data/test_usage/test_metadata.rb +104 -0
  49. data/test_usage/test_screenshot.rb +197 -0
  50. data/test_usage/test_storage.rb +52 -0
  51. metadata +46 -6
  52. data/lib/libvirt/error.rb +0 -6
  53. data/lib/libvirt/ffi/connection.rb +0 -84
  54. data/lib/libvirt/ffi/libvirt.rb +0 -17
  55. data/lib/libvirt/ffi/node_info.rb +0 -37
@@ -2,20 +2,35 @@
2
2
 
3
3
  module Libvirt
4
4
  class Domain
5
- def initialize(dom_ptr, conn)
5
+ def self.load_ref(dom_ptr)
6
+ ref_result = FFI::Domain.virDomainRef(dom_ptr)
7
+ raise Errors::LibError, "Couldn't retrieve domain reference" if ref_result.negative?
8
+
9
+ new(dom_ptr)
10
+ end
11
+
12
+ def initialize(dom_ptr)
6
13
  @dom_ptr = dom_ptr
7
- @conn = conn
8
- ObjectSpace.define_finalizer(self, proc { |obj_id|
9
- STDOUT.puts("finalized Libvirt::Domain #{obj_id.to_s(16)}")
10
- })
14
+
15
+ free = ->(obj_id) do
16
+ Util.log(:debug) { "Finalize Libvirt::Domain 0x#{obj_id.to_s(16)} @dom_ptr=#{@dom_ptr}," }
17
+ return unless @dom_ptr
18
+
19
+ fr_result = FFI::Domain.virDomainFree(@dom_ptr)
20
+ warn "Couldn't free Libvirt::Domain (0x#{obj_id.to_s(16)}) pointer #{@dom_ptr.address}" if fr_result.negative?
21
+ end
22
+ ObjectSpace.define_finalizer(self, free)
11
23
  end
12
24
 
13
25
  def get_state
14
26
  state = ::FFI::MemoryPointer.new(:int)
15
27
  reason = ::FFI::MemoryPointer.new(:int)
16
28
  result = FFI::Domain.virDomainGetState(@dom_ptr, state, reason, 0)
17
- raise Error, "Couldn't get domain state" if result < 0
18
- [state.read_int, reason.read_int]
29
+ raise Errors::LibError, "Couldn't get domain state" if result.negative?
30
+
31
+ state_sym = FFI::Domain.enum_type(:state)[state.read_int]
32
+ reason_sym = FFI::Domain.state_reason(state_sym, reason.read_int)
33
+ [state_sym, reason_sym]
19
34
  end
20
35
 
21
36
  def to_ptr
@@ -25,7 +40,8 @@ module Libvirt
25
40
  def uuid
26
41
  buff = ::FFI::MemoryPointer.new(:char, FFI::Domain::UUID_STRING_BUFLEN)
27
42
  result = FFI::Domain.virDomainGetUUIDString(@dom_ptr, buff)
28
- raise Error, "Couldn't get domain uuid" if result < 0
43
+ raise Errors::LibError, "Couldn't get domain uuid" if result.negative?
44
+
29
45
  buff.read_string
30
46
  end
31
47
 
@@ -56,5 +72,117 @@ module Libvirt
56
72
  def xml_desc(flags = 0)
57
73
  FFI::Domain.virDomainGetXMLDesc(@dom_ptr, flags)
58
74
  end
75
+
76
+ def screenshot(stream, display = 0)
77
+ dbg { "#screenshot stream=#{stream}, display=#{display}," }
78
+
79
+ mime_type, pointer = FFI::Domain.virDomainScreenshot(@dom_ptr, stream.to_ptr, display, 0)
80
+ raise Errors::LibError, "Couldn't attach domain screenshot" if pointer.null?
81
+
82
+ # free pointer required
83
+ mime_type
84
+ end
85
+
86
+ def free_domain
87
+ result = FFI::Domain.virDomainFree(@dom_ptr)
88
+ raise Errors::LibError, "Couldn't free domain" if result.negative?
89
+
90
+ @dom_ptr = nil
91
+ end
92
+
93
+ def start(flags = 0)
94
+ result = FFI::Domain.virDomainCreateWithFlags(@dom_ptr, flags)
95
+ raise Errors::LibError, "Couldn't start domain" if result.negative?
96
+ end
97
+
98
+ def reboot(flags = 0)
99
+ result = FFI::Domain.virDomainReboot(@dom_ptr, flags)
100
+ raise Errors::LibError, "Couldn't reboot domain" if result.negative?
101
+ end
102
+
103
+ def shutdown(flags = :ACPI_POWER_BTN)
104
+ result = FFI::Domain.virDomainShutdownFlags(@dom_ptr, flags)
105
+ raise Errors::LibError, "Couldn't shutdown domain" if result.negative?
106
+ end
107
+
108
+ def power_off(flags = 0)
109
+ result = FFI::Domain.virDomainDestroyFlags(@dom_ptr, flags)
110
+ raise Errors::LibError, "Couldn't power off domain" if result.negative?
111
+ end
112
+
113
+ def reset(flags = 0)
114
+ result = FFI::Domain.virDomainReset(@dom_ptr, flags)
115
+ raise Errors::LibError, "Couldn't reset domain" if result.negative?
116
+ end
117
+
118
+ def suspend
119
+ result = FFI::Domain.virDomainSuspend(@dom_ptr)
120
+ raise Errors::LibError, "Couldn't suspend domain" if result.negative?
121
+ end
122
+
123
+ def resume
124
+ result = FFI::Domain.virDomainResume(@dom_ptr)
125
+ raise Errors::LibError, "Couldn't resume domain" if result.negative?
126
+ end
127
+
128
+ # Undefine a domain.
129
+ # If the domain is running, it's converted to transient domain, without stopping it.
130
+ # If the domain is inactive, the domain configuration is removed.
131
+ # @param options_or_flags [Array<Symbol>,Hash{Symbol=>Boolean},Integer,Symbol,nil]
132
+ # @see Libvirt::FFI::Domain enum :undefine_flags_values for acceptable keys
133
+ # @see Libvirt::Util.parse_flags for possible argument values
134
+ # @raise [Libvirt::Errors::LibError] if operation failed
135
+ def undefine(options_or_flags = nil)
136
+ flags = Util.parse_flags options_or_flags, FFI::Domain.enum_type(:undefine_flags_values)
137
+ result = FFI::Domain.virDomainUndefineFlags(@dom_ptr, flags)
138
+ raise Errors::LibError, "Couldn't resume domain" if result.negative?
139
+ end
140
+
141
+ # After save_memory(:PAUSED) you need to call #start and #resume
142
+ # to move domain to the running state.
143
+ def save_memory(flags = :PAUSED)
144
+ result = FFI::Domain.virDomainManagedSave(@dom_ptr, flags)
145
+ raise Errors::LibError, "Couldn't save domain memory" if result.negative?
146
+ end
147
+
148
+ # Sets metadata
149
+ # @param metadata [String] xml node for element type, text for other types
150
+ # DESCRIPTION 0x0 - Operate on <description>
151
+ # TITLE 0x1 - Operate on <title>
152
+ # ELEMENT 0x2 - Operate on <metadata>
153
+ # @param type [Integer,Symbol] one of :ELEMENT, :TITLE, :DESCRIPTION
154
+ # @param key [String] xml key (required for type element)
155
+ # @param uri [String] xml namespace (required for type element)
156
+ # @param flags [Integer,Symbol] one off AFFECT_CURRENT, AFFECT_CONFIG, AFFECT_LIVE
157
+ # AFFECT_CURRENT 0x0 - Affect current domain state.
158
+ # AFFECT_LIVE 0x1 - Affect running domain state.
159
+ # AFFECT_CONFIG 0x2 - Affect persistent domain state.
160
+ # @raise [Libvirt::Errors::LibError] if operation failed
161
+ def set_metadata(metadata, type: :ELEMENT, key: nil, uri: nil, flags: :AFFECT_CURRENT)
162
+ result = FFI::Domain.virDomainSetMetadata(@dom_ptr, type, metadata, key, uri, flags)
163
+ raise Errors::LibError, "Couldn't set domain metadata" if result.negative?
164
+ end
165
+
166
+ # Retrieves metadata
167
+ # @param type [Integer,Symbol] one of :ELEMENT, :TITLE, :DESCRIPTION
168
+ # @param uri [String] xml namespace (required for type element)
169
+ # @param flags [Integer,Symbol] one off AFFECT_CURRENT, AFFECT_CONFIG, AFFECT_LIVE
170
+ # AFFECT_CURRENT 0x0 - Affect current domain state.
171
+ # AFFECT_LIVE 0x1 - Affect running domain state.
172
+ # AFFECT_CONFIG 0x2 - Affect persistent domain state.
173
+ # @raise [Libvirt::Errors::LibError] if operation failed
174
+ # @return [String] xml node, title, or description.
175
+ def get_metadata(type: :ELEMENT, uri: nil, flags: :AFFECT_CURRENT)
176
+ result = FFI::Domain.virDomainGetMetadata(@dom_ptr, type, uri, flags)
177
+ raise Errors::LibError, "Couldn't get domain metadata" if result.nil?
178
+
179
+ result
180
+ end
181
+
182
+ private
183
+
184
+ def dbg(&block)
185
+ Util.log(:debug, 'Libvirt::Domain', &block)
186
+ end
59
187
  end
60
188
  end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Libvirt
4
+ class DomainCallbackStorage
5
+ class CallbackDataStruct < ::FFI::Struct
6
+ layout :connection_pointer, :pointer,
7
+ :callback_id, :int
8
+ end
9
+
10
+ def initialize
11
+ @inner_storage = Hash.new { |h, key| h[key] = {} }
12
+ end
13
+
14
+ # @return [Array<2>]
15
+ # cb_data [Libvirt::DomainCallbackStorage::CallbackDataStruct],
16
+ # cb_data_free_func [FFI::Function]
17
+ def allocate_struct
18
+ dbg { '#allocate_struct' }
19
+
20
+ cb_data_ptr = ::FFI::MemoryPointer.new(:char, CallbackDataStruct.size, false)
21
+ cb_data = CallbackDataStruct.new(cb_data_ptr)
22
+ cb_data_free_func = FFI::Common.free_function do |pointer|
23
+ dbg { 'Libvirt::DomainCallbackStorage cb_data_free_func triggered' }
24
+ remove_struct(pointer)
25
+ end
26
+ [cb_data, cb_data_free_func]
27
+ end
28
+
29
+ def store_struct(cb_data, connection_pointer:, callback_id:, cb:, opaque:)
30
+ dbg { '#store_struct' }
31
+
32
+ cb_data[:connection_pointer] = connection_pointer
33
+ cb_data[:callback_id] = callback_id
34
+ @inner_storage[connection_pointer.address][callback_id] = { cb: cb, opaque: opaque, pointer: cb_data.pointer }
35
+ end
36
+
37
+ def remove_struct(pointer)
38
+ dbg { "#remove_struct pointer=#{pointer}" }
39
+
40
+ cb_data_struct = CallbackDataStruct.new(pointer)
41
+ connection_pointer = cb_data_struct[:connection_pointer]
42
+ callback_id = cb_data_struct[:callback_id]
43
+ dbg { "#remove_struct pointer=#{pointer}, connection_pointer=#{connection_pointer}, callback_id=#{callback_id}," }
44
+
45
+ cb_data = @inner_storage[connection_pointer.address].delete(callback_id)
46
+ @inner_storage.delete(connection_pointer.address) if @inner_storage[connection_pointer.address].empty?
47
+
48
+ cb_data[:opaque]
49
+ end
50
+
51
+ # @param [::FFI::Pointer]
52
+ # @return [Array<2>] cb [Proc], opaque [Object]
53
+ def retrieve_from_pointer(pointer)
54
+ dbg { "#retrieve_from_pointer pointer=#{pointer}," }
55
+
56
+ cb_data_struct = CallbackDataStruct.new(pointer)
57
+ connection_pointer = cb_data_struct[:connection_pointer]
58
+ callback_id = cb_data_struct[:callback_id]
59
+ cb_data = @inner_storage[connection_pointer.address][callback_id]
60
+ [cb_data[:cb], cb_data[:opaque]]
61
+ end
62
+
63
+ private
64
+
65
+ def dbg(&block)
66
+ Util.log(:debug, 'Libvirt::DomainCallbackStorage', &block)
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Libvirt
4
+ module Errors
5
+ class Error < StandardError
6
+ # Generic error
7
+ end
8
+
9
+ class LibError < Error
10
+ # Object contains detailed error information retrieved from libvirt.
11
+
12
+ ERROR_FIELDS = [:code, :domain, :message, :level].freeze
13
+
14
+ attr_reader :client_message,
15
+ :error_data,
16
+ :error_code,
17
+ :error_domain,
18
+ :error_message,
19
+ :error_level
20
+
21
+ # @param client_message [String, nil] optional client message
22
+ # When client_message ommited and virGetLastError return error
23
+ # message will be following: "ERROR_LEVEL: ERROR_NUMBER (ERROR_DOMAIN) ERROR_MESSAGE".
24
+ # When client message provided and virGetLastError return error
25
+ # message will be following: "CLIENT_MESSAGE\nERROR_LEVEL: ERROR_NUMBER (ERROR_DOMAIN) ERROR_MESSAGE".
26
+ # When client message is provided and virGetLastError return no error
27
+ # message will be following: "CLIENT_MESSAGE".
28
+ def initialize(client_message = nil)
29
+ @client_message = client_message
30
+ ptr = FFI::Error.virGetLastError
31
+ unless ptr.null?
32
+ struct = FFI::Error::Struct.new(ptr)
33
+ @error_data = struct.members.map { |m| [m, struct[m]] }.to_h
34
+ @error_code = error_data[:code]
35
+ @error_domain = error_data[:domain]
36
+ @error_message = error_data[:message]
37
+ @error_level = error_data[:level]
38
+ end
39
+
40
+ super(build_message)
41
+ end
42
+
43
+ private
44
+
45
+ def build_message
46
+ if error_data.nil?
47
+ client_message
48
+ elsif client_message.nil?
49
+ format '%<level>s: %<code>s (%<domain>s) %<message>s',
50
+ level: error_level,
51
+ code: error_code,
52
+ domain: error_domain,
53
+ message: error_message
54
+ else
55
+ format "%<client_message>s\n%<level>s: %<code>s (%<domain>s) %<message>s",
56
+ client_message: client_message,
57
+ level: error_level,
58
+ code: error_code,
59
+ domain: error_domain,
60
+ message: error_message
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -9,24 +9,32 @@ module Libvirt
9
9
  extend Forwardable
10
10
  extend SingleForwardable
11
11
 
12
- single_delegate [:register, :unregister, :registered?] => :instance
13
-
14
- Opaque = Struct.new(:cb, :opaque, :ff)
15
-
16
- class << self
17
- def invoke_handle_callback(watch, fd, events, opaque)
18
- cb = opaque.cb
19
- op = opaque.opaque
20
- Util.log(:debug) { "Libvirt::Event INVOKE_HANDLE_CALLBACK watch=#{watch} fd=#{fd} events=#{events} op=#{op}" }
21
- cb.call(watch, fd, events, op)
22
- end
12
+ single_delegate [
13
+ :register,
14
+ :unregister,
15
+ :registered?,
16
+ :debug,
17
+ :debug=,
18
+ :invoke_handle_callback,
19
+ :invoke_timeout_callback
20
+ ] => :instance
21
+
22
+ attr_accessor :debug
23
+
24
+ Opaque = Struct.new(:cb, :opaque, :free_func)
25
+
26
+ def invoke_handle_callback(watch, fd, events, opaque)
27
+ cb = opaque.cb
28
+ op = opaque.opaque
29
+ dbg { "INVOKE_HANDLE_CALLBACK watch=#{watch} fd=#{fd} events=#{events} op=#{op}" }
30
+ cb.call(watch, fd, events, op)
31
+ end
23
32
 
24
- def invoke_timeout_callback(timer, opaque)
25
- cb = opaque.cb
26
- op = opaque.opaque
27
- Util.log(:debug) { "Libvirt::Event INVOKE_TIMEOUT_CALLBACK timer=#{timer} op=#{op}" }
28
- cb.call(timer, op)
29
- end
33
+ def invoke_timeout_callback(timer, opaque)
34
+ cb = opaque.cb
35
+ op = opaque.opaque
36
+ dbg { "INVOKE_TIMEOUT_CALLBACK timer=#{timer} op=#{op}" }
37
+ cb.call(timer, op)
30
38
  end
31
39
 
32
40
  def registered?
@@ -51,20 +59,25 @@ module Libvirt
51
59
  true
52
60
  end
53
61
 
54
- def register(add_handle:, update_handle:, remove_handle:, add_timer:, update_timer:, remove_timer:)
62
+ def schedule_operation(&block)
63
+ @schedule.call(&block)
64
+ end
65
+
66
+ def register(add_handle:, update_handle:, remove_handle:, add_timer:, update_timer:, remove_timer:, schedule:) # rubocop:disable Metrics/ParameterLists
55
67
  @add_handle = add_handle
56
68
  @update_handle = update_handle
57
69
  @remove_handle = remove_handle
58
70
  @add_timer = add_timer
59
71
  @update_timer = update_timer
60
72
  @remove_timer = remove_timer
73
+ @schedule = schedule
61
74
 
62
- @add_handle_cb = FFI::Event.event_add_handle_func(&method(:_add_handle).to_proc)
63
- @update_handle_cb = ::FFI::Function.new(:void, [:int, :int], &method(:_update_handle).to_proc)
64
- @remove_handle_cb = ::FFI::Function.new(:int, [:int], &method(:_remove_handle).to_proc)
65
- @add_timer_cb = FFI::Event.event_add_timeout_func(&method(:_add_timer).to_proc)
66
- @update_timer_cb = ::FFI::Function.new(:void, [:int, :int], &method(:_update_timer).to_proc)
67
- @remove_timer_cb = ::FFI::Function.new(:int, [:int], &method(:_remove_timer).to_proc)
75
+ @add_handle_cb = FFI::Event.callback_function(:virEventAddHandleFunc, &method(:_add_handle))
76
+ @update_handle_cb = FFI::Event.callback_function(:virEventUpdateHandleFunc, &method(:_update_handle))
77
+ @remove_handle_cb = FFI::Event.callback_function(:virEventRemoveHandleFunc, &method(:_remove_handle))
78
+ @add_timer_cb = FFI::Event.callback_function(:virEventAddTimeoutFunc, &method(:_add_timer))
79
+ @update_timer_cb = FFI::Event.callback_function(:virEventUpdateTimeoutFunc, &method(:_update_timer))
80
+ @remove_timer_cb = FFI::Event.callback_function(:virEventRemoveTimeoutFunc, &method(:_remove_timer))
68
81
 
69
82
  FFI::Event.virEventRegisterImpl(
70
83
  @add_handle_cb,
@@ -79,45 +92,54 @@ module Libvirt
79
92
 
80
93
  private
81
94
 
82
- def _add_handle(fd, event, cb, opaque, ff)
83
- Util.log(:debug) { "Libvirt::Event ADD_HANDLE fd=#{fd}, #{event}=event, cb=#{cb}, opaque=#{opaque}, ff=#{ff}" }
84
- op = Opaque.new(cb, opaque, ff)
95
+ def _add_handle(fd, event, cb, opaque, free_func)
96
+ dbg { "ADD_HANDLE fd=#{fd}, #{event}=event, cb=#{cb}, opaque=#{opaque}, free_func=#{free_func}" }
97
+ op = Opaque.new(cb, opaque, free_func)
85
98
  @add_handle.call(fd, event, op)
86
99
  end
87
100
 
88
101
  def _update_handle(watch, event)
89
- Util.log(:debug) { "Libvirt::Event UPDATE_HANDLE watch=#{watch}, event=#{event}" }
102
+ dbg { "UPDATE_HANDLE watch=#{watch}, event=#{event}" }
90
103
  @update_handle.call(watch, event)
91
104
  end
92
105
 
93
106
  def _remove_handle(watch)
94
- Util.log(:debug) { "Libvirt::Event REMOVE_HANDLE watch=#{watch}" }
107
+ dbg { "REMOVE_HANDLE watch=#{watch}" }
95
108
  op = @remove_handle.call(watch)
96
- free_func = op.ff
109
+ free_func = op.free_func
97
110
  opaque = op.opaque
98
- free_func.call(opaque) unless free_func.null?
111
+ schedule_operation do
112
+ dbg { "REMOVE_HANDLE delayed free_func watch=#{watch}" }
113
+ free_func.call(opaque) unless free_func.null?
114
+ end
99
115
  0
100
116
  end
101
117
 
102
- def _add_timer(timeout, cb, opaque, ff)
103
- Util.log(:debug) { "Libvirt::Event ADD_TIMER timeout=#{timeout}, cb=#{cb}, opaque=#{opaque}, ff=#{ff}" }
104
- op = Opaque.new(cb, opaque, ff)
118
+ def _add_timer(timeout, cb, opaque, free_func)
119
+ dbg { "ADD_TIMER timeout=#{timeout}, cb=#{cb}, opaque=#{opaque}, free_func=#{free_func}" }
120
+ op = Opaque.new(cb, opaque, free_func)
105
121
  @add_timer.call(timeout, op)
106
122
  end
107
123
 
108
124
  def _update_timer(timer, timeout)
109
- Util.log(:debug) { "Libvirt::Event UPDATE_TIMER timer=#{timer}, timeout=#{timeout}" }
125
+ dbg { "UPDATE_TIMER timer=#{timer}, timeout=#{timeout}" }
110
126
  @update_timer.call(timer, timeout)
111
127
  end
112
128
 
113
129
  def _remove_timer(timer)
114
- Util.log(:debug) { "Libvirt::Event REMOVE_TIMER timer=#{timer}" }
130
+ dbg { "REMOVE_TIMER timer=#{timer}" }
115
131
  op = @remove_timer.call(timer)
116
- free_func = op.ff
132
+ free_func = op.free_func
117
133
  opaque = op.opaque
118
- free_func.call(opaque) unless free_func.null?
134
+ schedule_operation do
135
+ dbg { "REMOVE_TIMER async free_func timer=#{timer}" }
136
+ free_func.call(opaque) unless free_func.null?
137
+ end
119
138
  0
120
139
  end
121
140
 
141
+ def dbg(&block)
142
+ Util.log(:debug, 'Libvirt::Event', &block)
143
+ end
122
144
  end
123
145
  end