libvirt_ffi 0.2.1 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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