utilrb 3.1.0 → 3.2.0
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.
- checksums.yaml +5 -5
- data/lib/utilrb/event_loop.rb +51 -49
- data/lib/utilrb/exception/full_message.rb +2 -1
- data/lib/utilrb/hash/slice.rb +2 -5
- data/lib/utilrb/kernel/options.rb +3 -4
- data/lib/utilrb/logger/hierarchy.rb +36 -17
- data/lib/utilrb/module/dsl_attribute.rb +37 -25
- data/lib/utilrb/object/address.rb +15 -3
- data/lib/utilrb/object/attribute.rb +2 -1
- data/lib/utilrb/pkgconfig.rb +190 -101
- data/lib/utilrb/thread_pool.rb +29 -25
- data/lib/utilrb/version.rb +1 -1
- data/manifest.xml +1 -0
- data/utilrb.gemspec +1 -0
- metadata +20 -8
- data/.travis.yml +0 -11
data/lib/utilrb/pkgconfig.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
1
|
+
require "set"
|
|
2
|
+
require "shellwords"
|
|
3
3
|
|
|
4
4
|
module Utilrb
|
|
5
5
|
# Access to information from pkg-config(1)
|
|
@@ -32,7 +32,7 @@ module Utilrb
|
|
|
32
32
|
# pkg.static
|
|
33
33
|
#
|
|
34
34
|
# Arbitrary variables defined in the .pc file can be accessed with
|
|
35
|
-
#
|
|
35
|
+
#
|
|
36
36
|
# pkg.prefix
|
|
37
37
|
# pkg.libdir
|
|
38
38
|
#
|
|
@@ -62,7 +62,9 @@ module Utilrb
|
|
|
62
62
|
|
|
63
63
|
# Returns the pkg-config object that matches the given name, and
|
|
64
64
|
# optionally a version string
|
|
65
|
-
def self.get(name, version_spec = nil, preset_variables = Hash.new,
|
|
65
|
+
def self.get(name, version_spec = nil, preset_variables = Hash.new,
|
|
66
|
+
minimal: false, pkg_config_path: self.pkg_config_path, memo: Hash.new)
|
|
67
|
+
|
|
66
68
|
paths = find_all_package_files(name, pkg_config_path: pkg_config_path)
|
|
67
69
|
if paths.empty?
|
|
68
70
|
raise NotFound.new(name), "cannot find the pkg-config specification for #{name}"
|
|
@@ -74,14 +76,15 @@ module Utilrb
|
|
|
74
76
|
|
|
75
77
|
# Now try to find a matching spec
|
|
76
78
|
if match = find_matching_version(candidates, version_spec)
|
|
77
|
-
match
|
|
79
|
+
memo[[name, version_spec]] = [false, match]
|
|
78
80
|
else
|
|
79
|
-
raise NotFound, "found #{candidates.size} packages for #{name},
|
|
81
|
+
raise NotFound, "found #{candidates.size} packages for #{name},"\
|
|
82
|
+
" but none match the version specification #{version_spec}"
|
|
80
83
|
end
|
|
81
84
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
match.load_fields(memo: memo) unless minimal
|
|
86
|
+
|
|
87
|
+
memo[[name, version_spec]] = [true, match]
|
|
85
88
|
match
|
|
86
89
|
end
|
|
87
90
|
|
|
@@ -93,8 +96,8 @@ module Utilrb
|
|
|
93
96
|
# ...
|
|
94
97
|
# @return [PkgConfig] the pkg-config description
|
|
95
98
|
# @raise [NotFound] if the package is not found
|
|
96
|
-
def self.new(name, version_spec = nil, options
|
|
97
|
-
get(name, version_spec, options)
|
|
99
|
+
def self.new(name, version_spec = nil, **options)
|
|
100
|
+
get(name, version_spec, **options)
|
|
98
101
|
end
|
|
99
102
|
|
|
100
103
|
# Returns the first package in +candidates+ that match the given version
|
|
@@ -128,29 +131,30 @@ module Utilrb
|
|
|
128
131
|
end
|
|
129
132
|
|
|
130
133
|
# Exception raised when a request pkg-config file is not found
|
|
131
|
-
|
|
134
|
+
class NotFound < RuntimeError
|
|
132
135
|
# The name of the pkg-config package
|
|
133
|
-
|
|
136
|
+
attr_reader :name
|
|
134
137
|
|
|
135
|
-
|
|
136
|
-
|
|
138
|
+
def initialize(name); @name = name end
|
|
139
|
+
end
|
|
137
140
|
|
|
138
141
|
# Exception raised when invalid data is found in a pkg-config file
|
|
139
142
|
class Invalid < RuntimeError
|
|
140
143
|
# The name of the pkg-config package
|
|
141
|
-
|
|
144
|
+
attr_reader :name
|
|
142
145
|
|
|
143
|
-
|
|
146
|
+
def initialize(name); @name = name end
|
|
144
147
|
end
|
|
145
148
|
|
|
146
|
-
|
|
147
149
|
attr_reader :path
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
150
|
+
|
|
151
|
+
# The module name
|
|
152
|
+
attr_reader :name
|
|
151
153
|
attr_reader :description
|
|
154
|
+
|
|
152
155
|
# The module version as a string
|
|
153
156
|
attr_reader :raw_version
|
|
157
|
+
|
|
154
158
|
# The module version, as an array of integers
|
|
155
159
|
attr_reader :version
|
|
156
160
|
|
|
@@ -165,13 +169,13 @@ module Utilrb
|
|
|
165
169
|
# @return [Array<PkgConfig>]
|
|
166
170
|
attr_reader :requires
|
|
167
171
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
# Create a PkgConfig object for the package +name+
|
|
173
|
+
# Raises PkgConfig::NotFound if the module does not exist
|
|
174
|
+
def initialize(name)
|
|
175
|
+
@name = name
|
|
176
|
+
@fields = Hash.new
|
|
177
|
+
@variables = Hash.new
|
|
178
|
+
end
|
|
175
179
|
|
|
176
180
|
# Helper method that expands ${word} in +value+ using the name to value
|
|
177
181
|
# map +variables+
|
|
@@ -192,31 +196,38 @@ module Utilrb
|
|
|
192
196
|
value
|
|
193
197
|
end
|
|
194
198
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
199
|
+
class DependencyLoop < RuntimeError; end
|
|
200
|
+
|
|
201
|
+
def self.parse_dependencies(string, allow_loops: false, memo: Hash.new)
|
|
202
|
+
string = string.gsub(',', ' ')
|
|
203
|
+
packages = []
|
|
204
|
+
words = string.split(' ')
|
|
205
|
+
while !words.empty?
|
|
206
|
+
w = words.shift
|
|
207
|
+
if w =~ /[<>=]/
|
|
208
|
+
version = words.shift
|
|
209
|
+
if version =~ /[\d\.]+/
|
|
210
|
+
packages[-1][1] = "#{w} #{version}"
|
|
205
211
|
else
|
|
206
|
-
packages <<
|
|
212
|
+
packages << [version, nil]
|
|
207
213
|
end
|
|
214
|
+
else
|
|
215
|
+
packages << [w, nil]
|
|
208
216
|
end
|
|
209
217
|
end
|
|
210
|
-
|
|
211
218
|
result = packages.map do |dep|
|
|
212
|
-
|
|
213
|
-
if
|
|
214
|
-
|
|
219
|
+
finished, pkg = memo[dep]
|
|
220
|
+
if pkg
|
|
221
|
+
if allow_loops || finished
|
|
222
|
+
pkg
|
|
223
|
+
else
|
|
224
|
+
raise DependencyLoop, "found a dependency loop"
|
|
225
|
+
end
|
|
215
226
|
else
|
|
216
|
-
PkgConfig.get(dep)
|
|
227
|
+
PkgConfig.get(*dep, memo: memo)
|
|
217
228
|
end
|
|
218
229
|
end
|
|
219
|
-
result
|
|
230
|
+
result.compact
|
|
220
231
|
end
|
|
221
232
|
|
|
222
233
|
SHELL_VARS = %w{Cflags Libs Libs.private}
|
|
@@ -256,7 +267,6 @@ module Utilrb
|
|
|
256
267
|
end
|
|
257
268
|
end.compact
|
|
258
269
|
|
|
259
|
-
|
|
260
270
|
raw_variables, raw_fields = Hash.new, Hash.new
|
|
261
271
|
file.each do |line|
|
|
262
272
|
case line
|
|
@@ -271,7 +281,7 @@ module Utilrb
|
|
|
271
281
|
end
|
|
272
282
|
return raw_variables, raw_fields
|
|
273
283
|
end
|
|
274
|
-
|
|
284
|
+
|
|
275
285
|
def expand_variables(raw_variables)
|
|
276
286
|
raw_variables = raw_variables.dup
|
|
277
287
|
|
|
@@ -288,9 +298,9 @@ module Utilrb
|
|
|
288
298
|
end
|
|
289
299
|
variables
|
|
290
300
|
end
|
|
291
|
-
|
|
301
|
+
|
|
292
302
|
def expand_field(name, field)
|
|
293
|
-
if SHELL_VARS.include?(name)
|
|
303
|
+
if SHELL_VARS.include?(name)
|
|
294
304
|
value = Shellwords.shellsplit(field)
|
|
295
305
|
resolved = Array.new
|
|
296
306
|
while !value.empty?
|
|
@@ -310,17 +320,28 @@ module Utilrb
|
|
|
310
320
|
end
|
|
311
321
|
end
|
|
312
322
|
|
|
323
|
+
def builtin_variables(path)
|
|
324
|
+
{
|
|
325
|
+
"pcfiledir" => File.dirname(path),
|
|
326
|
+
"pc_sysrootdir" => sysrootdir
|
|
327
|
+
}
|
|
328
|
+
end
|
|
329
|
+
|
|
313
330
|
def load_variables(path, preset_variables = Hash.new)
|
|
314
331
|
raw_variables, raw_fields = parse(path)
|
|
315
332
|
raw_variables = preset_variables.merge(raw_variables)
|
|
316
|
-
expand_variables(
|
|
333
|
+
expand_variables(
|
|
334
|
+
raw_variables.merge(builtin_variables(path))
|
|
335
|
+
)
|
|
317
336
|
end
|
|
318
|
-
|
|
337
|
+
|
|
319
338
|
def load_minimal(path, preset_variables = Hash.new)
|
|
320
339
|
raw_variables, raw_fields = parse(path)
|
|
321
340
|
raw_variables = preset_variables.merge(raw_variables)
|
|
322
341
|
|
|
323
|
-
@variables = expand_variables(
|
|
342
|
+
@variables = expand_variables(
|
|
343
|
+
raw_variables.merge(builtin_variables(path))
|
|
344
|
+
)
|
|
324
345
|
if raw_fields['Version']
|
|
325
346
|
@raw_version = expand_field('Version', raw_fields['Version'])
|
|
326
347
|
else
|
|
@@ -333,7 +354,7 @@ module Utilrb
|
|
|
333
354
|
@path = path
|
|
334
355
|
end
|
|
335
356
|
|
|
336
|
-
def load_fields
|
|
357
|
+
def load_fields(memo: Hash.new)
|
|
337
358
|
fields = Hash.new
|
|
338
359
|
@raw_fields.each do |name, value|
|
|
339
360
|
fields[name] = expand_field(name, value)
|
|
@@ -344,27 +365,39 @@ module Utilrb
|
|
|
344
365
|
@description = (fields['Description'] || '')
|
|
345
366
|
|
|
346
367
|
# Get the requires/conflicts
|
|
347
|
-
@requires = PkgConfig.parse_dependencies(
|
|
348
|
-
|
|
349
|
-
@
|
|
368
|
+
@requires = PkgConfig.parse_dependencies(
|
|
369
|
+
fields['Requires'] || '', allow_loops: false, memo: memo)
|
|
370
|
+
@requires_private = PkgConfig.parse_dependencies(
|
|
371
|
+
fields['Requires.private'] || '', allow_loops: false, memo: memo)
|
|
372
|
+
@conflicts = PkgConfig.parse_dependencies(
|
|
373
|
+
fields['Conflicts'] || '', allow_loops: true, memo: memo)
|
|
350
374
|
|
|
351
375
|
# And finally resolve the compilation flags
|
|
352
|
-
|
|
376
|
+
cflags = fields['Cflags'] || []
|
|
377
|
+
cflags.uniq!
|
|
378
|
+
cflags -= self.class.default_search_path_I
|
|
379
|
+
cflags = apply_sysrootdir(cflags, "-I")
|
|
353
380
|
@requires.each do |pkg|
|
|
354
|
-
|
|
381
|
+
cflags.concat(pkg.raw_cflags)
|
|
355
382
|
end
|
|
356
383
|
@requires_private.each do |pkg|
|
|
357
|
-
|
|
384
|
+
cflags.concat(pkg.raw_cflags)
|
|
358
385
|
end
|
|
359
|
-
@cflags
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
386
|
+
@cflags = cflags
|
|
387
|
+
|
|
388
|
+
ldflags_public = fields['Libs'] || []
|
|
389
|
+
ldflags_public.uniq!
|
|
390
|
+
ldflags_private = ldflags_public + (fields['Libs.private'] || [])
|
|
391
|
+
ldflags_private.uniq!
|
|
392
|
+
|
|
393
|
+
ldflags_public -= self.class.default_search_path_L
|
|
394
|
+
ldflags_public = apply_sysrootdir(ldflags_public, "-L")
|
|
395
|
+
ldflags_private -= self.class.default_search_path_L
|
|
396
|
+
ldflags_private = apply_sysrootdir(ldflags_private, "-L")
|
|
397
|
+
@ldflags = {
|
|
398
|
+
false => ldflags_public,
|
|
399
|
+
true => ldflags_private
|
|
400
|
+
}
|
|
368
401
|
|
|
369
402
|
@ldflags_with_requires = {
|
|
370
403
|
true => @ldflags[true].dup,
|
|
@@ -387,7 +420,7 @@ module Utilrb
|
|
|
387
420
|
load_fields
|
|
388
421
|
end
|
|
389
422
|
|
|
390
|
-
|
|
423
|
+
def self.define_pkgconfig_action(action) # :nodoc:
|
|
391
424
|
class_eval <<-EOD, __FILE__, __LINE__+1
|
|
392
425
|
def pkgconfig_#{action.gsub(/-/, '_')}(static = false)
|
|
393
426
|
if static
|
|
@@ -397,8 +430,8 @@ module Utilrb
|
|
|
397
430
|
end
|
|
398
431
|
end
|
|
399
432
|
EOD
|
|
400
|
-
|
|
401
|
-
|
|
433
|
+
nil
|
|
434
|
+
end
|
|
402
435
|
|
|
403
436
|
def pkgconfig_variable(varname)
|
|
404
437
|
`pkg-config --variable=#{varname}`.strip
|
|
@@ -411,6 +444,7 @@ module Utilrb
|
|
|
411
444
|
if result.any?(&:empty?)
|
|
412
445
|
raise Invalid.new(name), "empty include directory (-I without argument) found in pkg-config package #{name}"
|
|
413
446
|
end
|
|
447
|
+
|
|
414
448
|
result
|
|
415
449
|
end
|
|
416
450
|
|
|
@@ -421,12 +455,38 @@ module Utilrb
|
|
|
421
455
|
if result.any?(&:empty?)
|
|
422
456
|
raise Invalid.new(name), "empty link directory (-L without argument) found in pkg-config package #{name}"
|
|
423
457
|
end
|
|
458
|
+
|
|
424
459
|
result
|
|
425
460
|
end
|
|
426
461
|
|
|
427
|
-
|
|
462
|
+
# A "new root" that should be prepended to -L and -I flags
|
|
463
|
+
def sysrootdir
|
|
464
|
+
ENV["PKG_CONFIG_SYSROOT_DIR"] || "/"
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
# @api private
|
|
468
|
+
#
|
|
469
|
+
# Apply {#sysrootdir} to all the given paths flags (-I or -L)
|
|
470
|
+
def apply_sysrootdir(entries, flag_name)
|
|
471
|
+
sysrootdir = self.sysrootdir
|
|
472
|
+
return entries if sysrootdir == "/"
|
|
473
|
+
|
|
474
|
+
entries.map do |v|
|
|
475
|
+
if v.start_with?(flag_name)
|
|
476
|
+
"#{flag_name}#{sysrootdir}#{v[2..-1]}"
|
|
477
|
+
else
|
|
478
|
+
v
|
|
479
|
+
end
|
|
480
|
+
end
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
ACTIONS = %w{cflags cflags-only-I cflags-only-other
|
|
428
484
|
libs libs-only-L libs-only-l libs-only-other}
|
|
429
|
-
|
|
485
|
+
ACTIONS.each { |action| define_pkgconfig_action(action) }
|
|
486
|
+
|
|
487
|
+
def conflicts
|
|
488
|
+
@conflicts
|
|
489
|
+
end
|
|
430
490
|
|
|
431
491
|
def raw_cflags
|
|
432
492
|
@cflags
|
|
@@ -495,13 +555,13 @@ module Utilrb
|
|
|
495
555
|
raw_libs_only_other(static).join(" ")
|
|
496
556
|
end
|
|
497
557
|
|
|
498
|
-
|
|
499
|
-
|
|
558
|
+
def method_missing(varname, *args, &proc) # :nodoc:
|
|
559
|
+
if args.empty?
|
|
500
560
|
variables[varname.to_s]
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
561
|
+
else
|
|
562
|
+
super(varname, *args, &proc)
|
|
563
|
+
end
|
|
564
|
+
end
|
|
505
565
|
|
|
506
566
|
def self.pkg_config_path
|
|
507
567
|
ENV['PKG_CONFIG_PATH']
|
|
@@ -509,9 +569,8 @@ module Utilrb
|
|
|
509
569
|
|
|
510
570
|
def self.each_pkgconfig_directory(pkg_config_path: self.pkg_config_path, &block)
|
|
511
571
|
return enum_for(__method__) if !block_given?
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
end
|
|
572
|
+
|
|
573
|
+
pkg_config_path.split(':').each(&block) if pkg_config_path
|
|
515
574
|
default_search_path.each(&block)
|
|
516
575
|
end
|
|
517
576
|
|
|
@@ -561,34 +620,64 @@ module Utilrb
|
|
|
561
620
|
end
|
|
562
621
|
|
|
563
622
|
|
|
564
|
-
|
|
565
|
-
NONEXISTENT_PATH_RX = /Cannot open directory (?:#\d+ )?'.*\/((?:lib|lib64|share)\/.*)' in package search path:.*/
|
|
623
|
+
PKGCONFIG_PATH_RX = %r{.*/((?:lib|lib64|share)/.*)}.freeze
|
|
566
624
|
|
|
567
625
|
# Returns the system-wide search path that is embedded in pkg-config
|
|
568
626
|
def self.default_search_path
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
627
|
+
@default_search_path ||=
|
|
628
|
+
`LANG=C pkg-config --variable pc_path pkg-config`
|
|
629
|
+
.strip
|
|
630
|
+
.split(":")
|
|
631
|
+
.grep(PKGCONFIG_PATH_RX)
|
|
632
|
+
.to_set
|
|
575
633
|
end
|
|
634
|
+
|
|
576
635
|
@default_search_path = nil
|
|
577
636
|
|
|
637
|
+
def self.arch_dir
|
|
638
|
+
return if @arch_dir == false
|
|
639
|
+
|
|
640
|
+
unless @arch_dir
|
|
641
|
+
suffix_with_arch =
|
|
642
|
+
default_search_suffixes
|
|
643
|
+
.find { |p| %r{^lib/[^/]+/pkgconfig} =~ p }
|
|
644
|
+
|
|
645
|
+
@arch_dir =
|
|
646
|
+
if suffix_with_arch
|
|
647
|
+
suffix_with_arch.split("/")[1]
|
|
648
|
+
else
|
|
649
|
+
false
|
|
650
|
+
end
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
@arch_dir
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
def self.default_search_path_L # rubocop:disable Naming/MethodName
|
|
657
|
+
unless @default_search_path_L
|
|
658
|
+
arch_dir = self.arch_dir
|
|
659
|
+
@default_search_path_L = # rubocop:disable Naming/VariableName
|
|
660
|
+
["-L/usr/lib", "-L/lib"]
|
|
661
|
+
.flat_map { |p| [p, "#{p}/#{arch_dir}"] }
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
@default_search_path_L
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
def self.default_search_path_I # rubocop:disable Naming/MethodName
|
|
668
|
+
@default_search_path_I ||= ["-I/usr/include"] # rubocop:disable Naming/VariableName
|
|
669
|
+
end
|
|
670
|
+
|
|
578
671
|
# Returns the system-wide standard suffixes that should be appended to
|
|
579
672
|
# new prefixes to find pkg-config files
|
|
580
673
|
def self.default_search_suffixes
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
to_set
|
|
589
|
-
@default_search_suffixes = found_paths | not_found
|
|
590
|
-
end
|
|
591
|
-
return @default_search_suffixes
|
|
674
|
+
@default_search_suffixes ||=
|
|
675
|
+
`LANG=C pkg-config --variable pc_path pkg-config`
|
|
676
|
+
.strip
|
|
677
|
+
.split(":")
|
|
678
|
+
.grep(PKGCONFIG_PATH_RX)
|
|
679
|
+
.map { |l| l.gsub(PKGCONFIG_PATH_RX, '\1') }
|
|
680
|
+
.to_set
|
|
592
681
|
end
|
|
593
682
|
end
|
|
594
683
|
end
|
data/lib/utilrb/thread_pool.rb
CHANGED
|
@@ -9,8 +9,8 @@ module Utilrb
|
|
|
9
9
|
#
|
|
10
10
|
# @example Using a thread pool of 10 threads
|
|
11
11
|
# pool = ThreadPool.new(10)
|
|
12
|
-
# 0.upto(9) do
|
|
13
|
-
# pool.process do
|
|
12
|
+
# 0.upto(9) do
|
|
13
|
+
# pool.process do
|
|
14
14
|
# sleep 1
|
|
15
15
|
# puts "done"
|
|
16
16
|
# end
|
|
@@ -40,7 +40,7 @@ module Utilrb
|
|
|
40
40
|
attr_reader :pool
|
|
41
41
|
|
|
42
42
|
# State of the task
|
|
43
|
-
#
|
|
43
|
+
#
|
|
44
44
|
# @return [:waiting,:running,:stopping,:finished,:terminated,:exception] the state
|
|
45
45
|
attr_reader :state
|
|
46
46
|
|
|
@@ -54,7 +54,7 @@ module Utilrb
|
|
|
54
54
|
# return [Thread] the thread
|
|
55
55
|
attr_reader :thread
|
|
56
56
|
|
|
57
|
-
# The time the task was queued
|
|
57
|
+
# The time the task was queued
|
|
58
58
|
#
|
|
59
59
|
# return [Time] the time
|
|
60
60
|
attr_accessor :queued_at
|
|
@@ -115,15 +115,15 @@ module Utilrb
|
|
|
115
115
|
def exception?; @state == :exception; end
|
|
116
116
|
|
|
117
117
|
# A new task which can be added to the work queue of a {ThreadPool}.
|
|
118
|
-
# If a sync key is given no task having the same key will be
|
|
118
|
+
# If a sync key is given no task having the same key will be
|
|
119
119
|
# executed in parallel which is useful for instance member calls
|
|
120
120
|
# which are not thread safe.
|
|
121
121
|
#
|
|
122
122
|
# @param [Hash] options The options of the task.
|
|
123
123
|
# @option options [Object] :sync_key The sync key
|
|
124
124
|
# @option options [Proc] :callback The callback
|
|
125
|
-
# @option options [Object] :default Default value returned when an error ocurred which was handled.
|
|
126
|
-
# @param [Array] args The arguments for the code block
|
|
125
|
+
# @option options [Object] :default Default value returned when an error ocurred which was handled.
|
|
126
|
+
# @param [Array] args The arguments for the code block
|
|
127
127
|
# @param [#call] block The code block
|
|
128
128
|
def initialize (options = Hash.new,*args, &block)
|
|
129
129
|
unless block
|
|
@@ -162,7 +162,7 @@ module Utilrb
|
|
|
162
162
|
# returns true if the task has a default return vale
|
|
163
163
|
# @return [Boolean]
|
|
164
164
|
def default?
|
|
165
|
-
@mutex.synchronize do
|
|
165
|
+
@mutex.synchronize do
|
|
166
166
|
@default != nil
|
|
167
167
|
end
|
|
168
168
|
end
|
|
@@ -170,7 +170,7 @@ module Utilrb
|
|
|
170
170
|
#sets all internal state to running
|
|
171
171
|
#call execute after that.
|
|
172
172
|
def pre_execute(pool=nil)
|
|
173
|
-
@mutex.synchronize do
|
|
173
|
+
@mutex.synchronize do
|
|
174
174
|
#store current thread to be able to terminate
|
|
175
175
|
#the thread
|
|
176
176
|
@pool = pool
|
|
@@ -182,7 +182,7 @@ module Utilrb
|
|
|
182
182
|
|
|
183
183
|
# Executes the task.
|
|
184
184
|
# Should be called from a worker thread after pre_execute was called.
|
|
185
|
-
# After execute returned and the task was deleted
|
|
185
|
+
# After execute returned and the task was deleted
|
|
186
186
|
# from any internal list finalize must be called
|
|
187
187
|
# to propagate the task state.
|
|
188
188
|
def execute()
|
|
@@ -200,7 +200,7 @@ module Utilrb
|
|
|
200
200
|
end
|
|
201
201
|
@stopped_at = Time.now
|
|
202
202
|
end
|
|
203
|
-
|
|
203
|
+
|
|
204
204
|
# propagates the tasks state
|
|
205
205
|
# should be called after execute
|
|
206
206
|
def finalize
|
|
@@ -225,7 +225,7 @@ module Utilrb
|
|
|
225
225
|
end
|
|
226
226
|
end
|
|
227
227
|
|
|
228
|
-
# Called from the worker thread when the work is done
|
|
228
|
+
# Called from the worker thread when the work is done
|
|
229
229
|
#
|
|
230
230
|
# @yield [Object,Exception] The callback
|
|
231
231
|
def callback(&block)
|
|
@@ -249,6 +249,10 @@ module Utilrb
|
|
|
249
249
|
0
|
|
250
250
|
end
|
|
251
251
|
end
|
|
252
|
+
|
|
253
|
+
def to_s
|
|
254
|
+
"#<Utilrb::ThreadPool::Task #{@state} #{@block}>"
|
|
255
|
+
end
|
|
252
256
|
end
|
|
253
257
|
|
|
254
258
|
# The minimum number of worker threads.
|
|
@@ -270,12 +274,12 @@ module Utilrb
|
|
|
270
274
|
#
|
|
271
275
|
# @return [Fixnum]
|
|
272
276
|
attr_reader :waiting
|
|
273
|
-
|
|
277
|
+
|
|
274
278
|
# The average execution time of a (running) task.
|
|
275
279
|
#
|
|
276
280
|
# @return [Float]
|
|
277
281
|
attr_reader :avg_run_time
|
|
278
|
-
|
|
282
|
+
|
|
279
283
|
# The average waiting time of a task before being executed.
|
|
280
284
|
#
|
|
281
285
|
# @return [Float]
|
|
@@ -300,7 +304,7 @@ module Utilrb
|
|
|
300
304
|
|
|
301
305
|
@tasks_waiting = [] # tasks waiting for execution
|
|
302
306
|
@tasks_running = [] # tasks which are currently running
|
|
303
|
-
|
|
307
|
+
|
|
304
308
|
# Statistics
|
|
305
309
|
@avg_run_time = 0 # average run time of a task in s [Float]
|
|
306
310
|
@avg_wait_time = 0 # average time a task has to wait for execution in s [Float]
|
|
@@ -370,10 +374,10 @@ module Utilrb
|
|
|
370
374
|
end
|
|
371
375
|
|
|
372
376
|
# Number of tasks waiting for execution
|
|
373
|
-
#
|
|
377
|
+
#
|
|
374
378
|
# @return [Fixnum] the number of tasks
|
|
375
379
|
def backlog
|
|
376
|
-
@mutex.synchronize do
|
|
380
|
+
@mutex.synchronize do
|
|
377
381
|
@tasks_waiting.length
|
|
378
382
|
end
|
|
379
383
|
end
|
|
@@ -396,7 +400,7 @@ module Utilrb
|
|
|
396
400
|
process_with_options(nil,*args,&block)
|
|
397
401
|
end
|
|
398
402
|
|
|
399
|
-
# Returns true if a worker thread is currently processing a task
|
|
403
|
+
# Returns true if a worker thread is currently processing a task
|
|
400
404
|
# and no work is queued
|
|
401
405
|
#
|
|
402
406
|
# @return [Boolean]
|
|
@@ -426,7 +430,7 @@ module Utilrb
|
|
|
426
430
|
# safe.
|
|
427
431
|
#
|
|
428
432
|
# @param [Object] sync_key The sync key
|
|
429
|
-
# @yield [*args] the code block block
|
|
433
|
+
# @yield [*args] the code block block
|
|
430
434
|
# @return [Object] The result of the code block
|
|
431
435
|
def sync(sync_key,*args,&block)
|
|
432
436
|
raise ArgumentError,"no sync key" unless sync_key
|
|
@@ -454,7 +458,7 @@ module Utilrb
|
|
|
454
458
|
#
|
|
455
459
|
# @param [Object] sync_key The sync key
|
|
456
460
|
# @param [Float] timeout The timeout
|
|
457
|
-
# @yield [*args] the code block block
|
|
461
|
+
# @yield [*args] the code block block
|
|
458
462
|
# @return [Object] The result of the code block
|
|
459
463
|
def sync_timeout(sync_key,timeout,*args,&block)
|
|
460
464
|
raise ArgumentError,"no sync key" unless sync_key
|
|
@@ -480,14 +484,14 @@ module Utilrb
|
|
|
480
484
|
end
|
|
481
485
|
|
|
482
486
|
# Processes the given {Task} as soon as the next thread is available
|
|
483
|
-
#
|
|
487
|
+
#
|
|
484
488
|
# @param [Task] task The task.
|
|
485
489
|
# @return [Task]
|
|
486
490
|
def <<(task)
|
|
487
491
|
raise "cannot add task #{task} it is still running" if task.thread
|
|
488
492
|
task.reset if task.finished?
|
|
489
493
|
@mutex.synchronize do
|
|
490
|
-
if shutdown?
|
|
494
|
+
if shutdown?
|
|
491
495
|
raise "unable to add work while shutting down"
|
|
492
496
|
end
|
|
493
497
|
task.queued_at = Time.now
|
|
@@ -500,7 +504,7 @@ module Utilrb
|
|
|
500
504
|
task
|
|
501
505
|
end
|
|
502
506
|
|
|
503
|
-
# Trims the number of threads if threads are waiting for work and
|
|
507
|
+
# Trims the number of threads if threads are waiting for work and
|
|
504
508
|
# the number of spawned threads is higher than the minimum number.
|
|
505
509
|
#
|
|
506
510
|
# @param [boolean] force Trim even if no thread is waiting.
|
|
@@ -551,12 +555,12 @@ module Utilrb
|
|
|
551
555
|
|
|
552
556
|
private
|
|
553
557
|
|
|
554
|
-
#calculates the moving average
|
|
558
|
+
#calculates the moving average
|
|
555
559
|
def moving_average(current_val,new_val)
|
|
556
560
|
return new_val if current_val == 0
|
|
557
561
|
current_val * 0.95 + new_val * 0.05
|
|
558
562
|
end
|
|
559
|
-
|
|
563
|
+
|
|
560
564
|
# spawns a worker thread
|
|
561
565
|
# must be called from a synchronized block
|
|
562
566
|
def spawn_thread
|
data/lib/utilrb/version.rb
CHANGED