├── .clang-format ├── .gitignore ├── .travis.yml ├── .travis_build_config.rb ├── README.md ├── Rakefile ├── build_config.rb ├── example ├── blkio.rb ├── cpu.rb ├── cpu_and_core.rb └── cpuset.rb ├── mrbgem.rake ├── mrblib └── cgroup.rb └── src ├── mrb_cgroup.c └── mrb_cgroup.h /.clang-format: -------------------------------------------------------------------------------- 1 | # requires clang-format >= 3.6 2 | BasedOnStyle: "LLVM" 3 | IndentWidth: 4 4 | ColumnLimit: 120 5 | BreakBeforeBraces: Linux 6 | AllowShortFunctionsOnASingleLine: None 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | mruby/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | compiler: 3 | - gcc 4 | - clang 5 | before_install: 6 | - sudo apt-get -qq update 7 | install: 8 | - sudo apt-get -qq install rake bison git gperf libpam0g-dev autotools-dev cgroup-lite 9 | - gem install rake 10 | env: 11 | - MRUBY_VERSION=1.2.0 12 | - MRUBY_VERSION=1.3.0 13 | - MRUBY_VERSION=master 14 | script: 15 | - rake 16 | -------------------------------------------------------------------------------- /.travis_build_config.rb: -------------------------------------------------------------------------------- 1 | MRuby::Build.new do |conf| 2 | toolchain :gcc 3 | conf.gembox 'default' 4 | conf.gem '../mruby-cgroup' 5 | end 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cgroup Module for mruby [![Build Status](https://travis-ci.org/matsumotory/mruby-cgroup.svg?branch=master)](https://travis-ci.org/matsumotory/mruby-cgroup) 2 | mruby cgroup module using libcgroup 3 | 4 | ## install by mrbgems 5 | - add conf.gem line to `build_config.rb` 6 | ```ruby 7 | MRuby::Build.new do |conf| 8 | 9 | # ... (snip) ... 10 | 11 | conf.gem :git => 'https://github.com/matsumoto-r/mruby-cgroup.git' 12 | end 13 | ``` 14 | 15 | ## example 16 | 17 | ```ruby 18 | rate = Cgroup::CPU.new "test" 19 | core = Cgroup::CPUSET.new "test" 20 | 21 | rate.cfs_quota_us = 30000 22 | core.cpus = core.mems = "0" 23 | 24 | rate.create 25 | core.create 26 | 27 | # CPU core 0 and rate 30% 28 | puts "attach /test group with cpu core 0 and rate 30%" 29 | rate.attach 30 | core.attach 31 | (1..100000000).each do |i| end 32 | 33 | # CPU core 2 and rate 50% 34 | puts "attach /test group with cpu core 2 and rate 50%" 35 | rate.cfs_quota_us = 50000 36 | core.cpus = core.mems = "2" 37 | rate.modify 38 | core.modify 39 | (1..100000000).each do |i| end 40 | 41 | # CPU core 0,1,2 and rate 90% 42 | puts "attach /test group with cpu core 0,1,2 and rate 90%" 43 | rate.cfs_quota_us = 90000 44 | core.cpus = core.mems = "0-2" 45 | rate.modify 46 | core.modify 47 | (1..100000000).each do |i| end 48 | 49 | puts "delete /test group" 50 | rate.delete 51 | core.delete 52 | ``` 53 | 54 | # License 55 | under the MIT License: 56 | 57 | * http://www.opensource.org/licenses/mit-license.php 58 | 59 | 60 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | MRUBY_CONFIG=File.expand_path(ENV["MRUBY_CONFIG"] || "build_config.rb") 2 | MRUBY_VERSION=ENV["MRUBY_VERSION"] || "master" 3 | 4 | file :mruby do 5 | #sh "wget -O mruby.tar.gz https://github.com/mruby/mruby/archive/#{MRUBY_VERSION}.tar.gz" 6 | #sh "tar -xvzf mruby.tar.gz" 7 | #sh "rm mruby.tar.gz" 8 | #sh "mv mruby-#{MRUBY_VERSION} mruby" 9 | sh "git clone --depth=1 git://github.com/mruby/mruby.git" 10 | end 11 | 12 | desc "compile binary" 13 | task :compile => :mruby do 14 | sh "cd mruby && MRUBY_CONFIG=#{MRUBY_CONFIG} rake all" 15 | end 16 | 17 | desc "test" 18 | task :test => :mruby do 19 | sh "cd mruby && MRUBY_CONFIG=#{MRUBY_CONFIG} rake all test" 20 | end 21 | 22 | desc "cleanup" 23 | task :clean do 24 | sh "cd mruby && rake deep_clean" 25 | end 26 | 27 | task :default => :test 28 | -------------------------------------------------------------------------------- /build_config.rb: -------------------------------------------------------------------------------- 1 | MRuby::Build.new do |conf| 2 | # load specific toolchain settings 3 | toolchain :gcc 4 | 5 | # Use mrbgems 6 | # conf.gem 'examples/mrbgems/ruby_extension_example' 7 | # conf.gem 'examples/mrbgems/c_extension_example' do |g| 8 | # g.cc.flags << '-g' # append cflags in this gem 9 | # end 10 | # conf.gem 'examples/mrbgems/c_and_ruby_extension_example' 11 | # conf.gem :github => 'masuidrive/mrbgems-example', :branch => 'master' 12 | # conf.gem :git => 'git@github.com:masuidrive/mrbgems-example.git', :branch => 'master', :options => '-v' 13 | 14 | # include the default GEMs 15 | conf.gembox 'default' 16 | conf.gem File.expand_path(File.dirname(__FILE__)) 17 | conf.enable_test 18 | 19 | # C compiler settings 20 | # conf.cc do |cc| 21 | # cc.command = ENV['CC'] || 'gcc' 22 | # cc.flags = [ENV['CFLAGS'] || %w()] 23 | # cc.include_paths = ["#{root}/include"] 24 | # cc.defines = %w(DISABLE_GEMS) 25 | # cc.option_include_path = '-I%s' 26 | # cc.option_define = '-D%s' 27 | # cc.compile_options = "%{flags} -MMD -o %{outfile} -c %{infile}" 28 | # end 29 | 30 | # mrbc settings 31 | # conf.mrbc do |mrbc| 32 | # mrbc.compile_options = "-g -B%{funcname} -o-" # The -g option is required for line numbers 33 | # end 34 | 35 | # Linker settings 36 | # conf.linker do |linker| 37 | # linker.command = ENV['LD'] || 'gcc' 38 | # linker.flags = [ENV['LDFLAGS'] || []] 39 | # linker.flags_before_libraries = [] 40 | # linker.libraries = %w() 41 | # linker.flags_after_libraries = [] 42 | # linker.library_paths = [] 43 | # linker.option_library = '-l%s' 44 | # linker.option_library_path = '-L%s' 45 | # linker.link_options = "%{flags} -o %{outfile} %{objs} %{libs}" 46 | # end 47 | 48 | # Archiver settings 49 | # conf.archiver do |archiver| 50 | # archiver.command = ENV['AR'] || 'ar' 51 | # archiver.archive_options = 'rs %{outfile} %{objs}' 52 | # end 53 | 54 | # Parser generator settings 55 | # conf.yacc do |yacc| 56 | # yacc.command = ENV['YACC'] || 'bison' 57 | # yacc.compile_options = '-o %{outfile} %{infile}' 58 | # end 59 | 60 | # gperf settings 61 | # conf.gperf do |gperf| 62 | # gperf.command = 'gperf' 63 | # gperf.compile_options = '-L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k"1,3,$" %{infile} > %{outfile}' 64 | # end 65 | 66 | # file extensions 67 | # conf.exts do |exts| 68 | # exts.object = '.o' 69 | # exts.executable = '' # '.exe' if Windows 70 | # exts.library = '.a' 71 | # end 72 | 73 | # file separetor 74 | # conf.file_separator = '/' 75 | end 76 | 77 | # Define cross build settings 78 | # MRuby::CrossBuild.new('32bit') do |conf| 79 | # toolchain :gcc 80 | # 81 | # conf.cc.flags << "-m32" 82 | # conf.linker.flags << "-m32" 83 | # 84 | # conf.build_mrbtest_lib_only 85 | # 86 | # conf.gem 'examples/mrbgems/c_and_ruby_extension_example' 87 | # 88 | # conf.test_runner.command = 'env' 89 | # 90 | # end 91 | -------------------------------------------------------------------------------- /example/blkio.rb: -------------------------------------------------------------------------------- 1 | c = Cgroup::BLKIO.new "/test" 2 | if !c.exist? 3 | puts "create cgroup cpu /test" 4 | c.throttle_write_bps_device = "8:0 100000000" 5 | c.create 6 | end 7 | 8 | # write bps 100Mbps 9 | puts "attach /test group with write bps 100Mbps" 10 | c.attach 11 | # I/O processing now 12 | c.detach 13 | puts "detach /test group with write bps 100Mbps" 14 | 15 | c.throttle_write_bps_device = "8:0 100000000" 16 | c.create 17 | end 18 | 19 | # read iops 20000iops 20 | puts "attach /test group with read iops 20000" 21 | c.throttle_read_iops_device = 20000 22 | c.modify 23 | c.attach 24 | # I/O processing now 25 | c.detach 26 | puts "detach /test group with write bps 100Mbps" 27 | 28 | if c.exist? 29 | puts "delete /test group" 30 | c.delete 31 | end 32 | 33 | -------------------------------------------------------------------------------- /example/cpu.rb: -------------------------------------------------------------------------------- 1 | c = Cgroup::CPU.new "/test" 2 | if !c.exist? 3 | puts "create cgroup cpu /test" 4 | c.cfs_quota_us = 30000 5 | c.create 6 | end 7 | 8 | # CPU 30% 9 | puts "attach /test group with cpu 30%" 10 | c.attach 11 | (1..10000000).each do |i| end 12 | c.detach 13 | puts "detach /test group with cpu 30%" 14 | 15 | # CPU 100% 16 | puts "run with cpu 100% !!" 17 | (1..100000000).each do |i| end 18 | 19 | # CPU 10% 20 | c.cfs_quota_us = 10000 21 | c.modify 22 | c.attach 23 | puts "attach /test group with cpu 10%" 24 | (1..10000000).each do |i| end 25 | puts "detach /test group" 26 | c.detach 27 | 28 | if c.exist? 29 | puts "delete /test group" 30 | c.delete 31 | end 32 | 33 | -------------------------------------------------------------------------------- /example/cpu_and_core.rb: -------------------------------------------------------------------------------- 1 | rate = Cgroup::CPU.new "test" 2 | core = Cgroup::CPUSET.new "test" 3 | 4 | rate.cfs_quota_us = 30000 5 | core.cpus = core.mems = "0" 6 | 7 | rate.create 8 | core.create 9 | 10 | # CPU core 0 and rate 30% 11 | puts "attach /test group with cpu core 0 and rate 30%" 12 | rate.attach 13 | core.attach 14 | (1..100000000).each do |i| end 15 | 16 | # CPU core 2 and rate 50% 17 | puts "attach /test group with cpu core 2 and rate 50%" 18 | rate.cfs_quota_us = 50000 19 | core.cpus = core.mems = "2" 20 | rate.modify 21 | core.modify 22 | (1..100000000).each do |i| end 23 | 24 | # CPU core 0,1,2 and rate 90% 25 | puts "attach /test group with cpu core 0,1,2 and rate 90%" 26 | rate.cfs_quota_us = 90000 27 | core.cpus = core.mems = "0-2" 28 | rate.modify 29 | core.modify 30 | (1..100000000).each do |i| end 31 | 32 | puts "delete /test group" 33 | rate.delete 34 | core.delete 35 | 36 | -------------------------------------------------------------------------------- /example/cpuset.rb: -------------------------------------------------------------------------------- 1 | c = Cgroup::CPUSET.new "/test" 2 | if !c.exist? 3 | puts "create cgroup cpuset /test" 4 | c.cpus = c.mems = "0" 5 | c.create 6 | end 7 | 8 | # CPU core 0 9 | puts "attach /test group with cpu core 0" 10 | c.attach 11 | (1..100000000).each do |i| end 12 | c.detach 13 | puts "detach /test group with cpu core 0" 14 | 15 | # CPU core 2 16 | puts "attach /test group with cpu core 2" 17 | c.cpus = c.mems = "2" 18 | c.modify 19 | c.attach 20 | (1..100000000).each do |i| end 21 | c.detach 22 | puts "detach /test group with cpu core 2" 23 | 24 | # CPU core 0,1,2 25 | puts "attach /test group with cpu core 0,1,2" 26 | c.cpus = c.mems = "0-2" 27 | c.modify 28 | c.attach 29 | (1..100000000).each do |i| end 30 | c.detach 31 | puts "detach /test group with cpu core 0,1,2" 32 | 33 | # CPU core 0,1,2,5 34 | puts "attach /test group with cpu core 0,1,2,5" 35 | c.cpus = c.mems = "0-2,5" 36 | c.modify 37 | c.attach 38 | (1..100000000).each do |i| end 39 | c.detach 40 | puts "detach /test group with cpu core 0,1,2,5" 41 | 42 | if c.exist? 43 | puts "delete /test group" 44 | c.delete 45 | end 46 | 47 | -------------------------------------------------------------------------------- /mrbgem.rake: -------------------------------------------------------------------------------- 1 | MRuby::Gem::Specification.new('mruby-cgroup') do |spec| 2 | spec.license = 'MIT' 3 | spec.authors = 'MATSUMOTO Ryosuke' 4 | spec.linker.libraries.concat ['pthread', 'rt'] 5 | 6 | def cgroup_available? 7 | `grep -q cpu /proc/self/cgroup` 8 | $?.success? 9 | end 10 | 11 | unless cgroup_available? 12 | puts "skip libcgroup build" 13 | next 14 | end 15 | 16 | next if spec.respond_to?(:search_package) && spec.search_package('libcgroup') 17 | 18 | require 'open3' 19 | 20 | def libcgroup_dir(b); "#{b.build_dir}/libcgroup"; end 21 | def libcgroup_build_dir(b); "#{b.build_dir}/libcgroup/build"; end 22 | 23 | task :clean do 24 | FileUtils.rm_rf [libcgroup_dir(build)] 25 | end 26 | 27 | def run_command env, command 28 | STDOUT.sync = true 29 | puts "EXEC\t[mruby-cgroup] #{command}" 30 | Open3.popen2e(env, command) do |stdin, stdout, thread| 31 | print stdout.read 32 | fail "#{command} failed" if thread.value != 0 33 | end 34 | end 35 | 36 | file libcgroup_dir(build) do 37 | FileUtils.mkdir_p build.build_dir 38 | 39 | unless File.exists? libcgroup_dir(build) 40 | Dir.chdir(build.build_dir) do 41 | e = {} 42 | run_command e, 'git clone git://github.com/matsumoto-r/libcgroup.git' 43 | end 44 | end 45 | end 46 | 47 | file libfile("#{libcgroup_build_dir(build)}/lib/libcgroup") => libcgroup_dir(build) do 48 | Dir.chdir libcgroup_dir(build) do 49 | e = { 50 | 'CC' => "#{spec.build.cc.command} #{spec.build.cc.flags.join(' ')}", 51 | 'CXX' => "#{spec.build.cxx.command} #{spec.build.cxx.flags.join(' ')}", 52 | 'LD' => "#{spec.build.linker.command} #{spec.build.linker.flags.join(' ')}", 53 | 'AR' => spec.build.archiver.command, 54 | 'PREFIX' => libcgroup_build_dir(build) 55 | } 56 | 57 | run_command e, "git checkout ce167ed16147bb68fa1b31633b19de77780d5f2b ." 58 | run_command e, "autoreconf --force --install" 59 | run_command e, "./configure --prefix=#{libcgroup_build_dir(build)} --enable-static --disable-shared" 60 | run_command e, "make" 61 | run_command e, "make install" 62 | end 63 | end 64 | 65 | file libfile("#{build.build_dir}/lib/libmruby") => libfile("#{libcgroup_build_dir(build)}/lib/libcgroup") 66 | 67 | spec.cc.include_paths << "#{libcgroup_build_dir(build)}/include" 68 | spec.linker.flags_before_libraries << libfile("#{libcgroup_build_dir(build)}/lib/libcgroup") 69 | end 70 | -------------------------------------------------------------------------------- /mrblib/cgroup.rb: -------------------------------------------------------------------------------- 1 | module Cgroup 2 | def root_attach root 3 | if !root.exist? 4 | raise "root group not found" 5 | end 6 | root.attach 7 | end 8 | class CPU 9 | def detach 10 | root_attach Cgroup::CPU.new "/" 11 | end 12 | end 13 | class CPUSET 14 | def detach 15 | root_attach Cgroup::CPUSET.new "/" 16 | end 17 | end 18 | class BLKIO 19 | def detach 20 | root_attach Cgroup::BLKIO.new "/" 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /src/mrb_cgroup.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** mrb_cgroup - cgroup module for mruby 3 | ** 4 | ** Copyright (c) mod_mruby developers 2012- 5 | ** 6 | ** Permission is hereby granted, free of charge, to any person obtaining 7 | ** a copy of this software and associated documentation files (the 8 | ** "Software"), to deal in the Software without restriction, including 9 | ** without limitation the rights to use, copy, modify, merge, publish, 10 | ** distribute, sublicense, and/or sell copies of the Software, and to 11 | ** permit persons to whom the Software is furnished to do so, subject to 12 | ** the following conditions: 13 | ** 14 | ** The above copyright notice and this permission notice shall be 15 | ** included in all copies or substantial portions of the Software. 16 | ** 17 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | ** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | ** 25 | ** [ MIT license: http://www.opensource.org/licenses/mit-license.php ] 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "mruby.h" 36 | #include "mruby/array.h" 37 | #include "mruby/class.h" 38 | #include "mruby/data.h" 39 | #include "mruby/numeric.h" 40 | #include "mruby/string.h" 41 | #include "mruby/variable.h" 42 | 43 | #define BLKIO_STRING_SIZE 64 44 | #define DONE mrb_gc_arena_restore(mrb, 0); 45 | 46 | typedef enum { 47 | MRB_CGROUP_cpu, 48 | MRB_CGROUP_cpuset, 49 | MRB_CGROUP_cpuacct, 50 | MRB_CGROUP_blkio, 51 | MRB_CGROUP_memory, 52 | MRB_CGROUP_pids 53 | } group_type_t; 54 | typedef struct cgroup cgroup_t; 55 | typedef struct cgroup_controller cgroup_controller_t; 56 | typedef struct { 57 | int already_exist; 58 | mrb_value group_name; 59 | group_type_t type; 60 | cgroup_t *cg; 61 | cgroup_controller_t *cgc; 62 | } mrb_cgroup_context; 63 | 64 | // 65 | // private 66 | // 67 | 68 | static void mrb_cgroup_context_free(mrb_state *mrb, void *p) 69 | { 70 | mrb_cgroup_context *ctx = p; 71 | // cgroup_free_controllers(c->cg); 72 | cgroup_free(&ctx->cg); 73 | } 74 | 75 | static const struct mrb_data_type mrb_cgroup_context_type = { 76 | "mrb_cgroup_context", mrb_cgroup_context_free, 77 | }; 78 | 79 | static mrb_cgroup_context *mrb_cgroup_get_context(mrb_state *mrb, mrb_value self, const char *ctx_flag) 80 | { 81 | mrb_cgroup_context *c; 82 | mrb_value context; 83 | 84 | context = mrb_iv_get(mrb, self, mrb_intern_cstr(mrb, ctx_flag)); 85 | Data_Get_Struct(mrb, context, &mrb_cgroup_context_type, c); 86 | if (!c) 87 | mrb_raise(mrb, E_RUNTIME_ERROR, "get mrb_cgroup_context failed"); 88 | 89 | return c; 90 | } 91 | 92 | // 93 | // group 94 | // 95 | 96 | static mrb_value mrb_cgroup_create(mrb_state *mrb, mrb_value self) 97 | { 98 | int code; 99 | mrb_cgroup_context *mrb_cg_cxt = mrb_cgroup_get_context(mrb, self, "mrb_cgroup_context"); 100 | 101 | // BUG1 : cgroup_create_cgroup returns an error(Invalid argument:50016:ECGOTHER), despite actually succeeding 102 | // BUG2 : cgroup_delete_cgroup returns an error(This kernel does not support this 103 | // feature:50029:ECGCANTSETVALUE), 104 | // despite actually succeeding 105 | // REFS : libcgroup/src/api.c 1620 - 1630 comments 106 | // 107 | // error = cg_set_control_value(path, 108 | // cgroup->controller[k]->values[j]->value); 109 | // /* 110 | // * Should we undo, what we've done in the loops above? 111 | // * An error should not be treated as fatal, since we 112 | // * have several read-only files and several files that 113 | // * are only conditionally created in the child. 114 | // * 115 | // * A middle ground would be to track that there 116 | // * was an error and return a diagnostic value-- 117 | // * callers don't get context for the error, but can 118 | // * ignore it specifically if they wish. 119 | // */ 120 | // if (error) { 121 | // cgroup_dbg("failed to set %s: %s (%d)\n", 122 | // path, 123 | // cgroup_strerror(error), error); 124 | // retval = ECGCANTSETVALUE; 125 | // continue; 126 | // } 127 | // 128 | 129 | if ((code = cgroup_create_cgroup(mrb_cg_cxt->cg, 1)) && code != ECGOTHER && code != ECGCANTSETVALUE) { 130 | mrb_raisef(mrb, E_RUNTIME_ERROR, "cgroup_create failed: %S(%S)", mrb_str_new_cstr(mrb, cgroup_strerror(code)), 131 | mrb_fixnum_value(code)); 132 | } 133 | mrb_cg_cxt->already_exist = 1; 134 | mrb_iv_set(mrb, self, mrb_intern_cstr(mrb, "mrb_cgroup_context"), 135 | mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &mrb_cgroup_context_type, (void *)mrb_cg_cxt))); 136 | 137 | return self; 138 | } 139 | 140 | static mrb_value mrb_cgroup_delete(mrb_state *mrb, mrb_value self) 141 | { 142 | int code; 143 | mrb_cgroup_context *mrb_cg_cxt = mrb_cgroup_get_context(mrb, self, "mrb_cgroup_context"); 144 | 145 | // BUG1 : cgroup_delete_cgroup returns an error(No such file or directory:50016:ECGOTHER), despite actually 146 | // succeeding 147 | if ((code = cgroup_delete_cgroup(mrb_cg_cxt->cg, 1)) && code != ECGOTHER) { 148 | mrb_raisef(mrb, E_RUNTIME_ERROR, "cgroup_delete faild: %S(%S)", mrb_str_new_cstr(mrb, cgroup_strerror(code)), 149 | mrb_fixnum_value(code)); 150 | } 151 | 152 | return self; 153 | } 154 | 155 | static mrb_value mrb_cgroup_exist_p(mrb_state *mrb, mrb_value self) 156 | { 157 | mrb_cgroup_context *mrb_cg_cxt = mrb_cgroup_get_context(mrb, self, "mrb_cgroup_context"); 158 | return (mrb_cg_cxt->already_exist) ? mrb_true_value() : mrb_false_value(); 159 | } 160 | 161 | // 162 | // task 163 | // 164 | 165 | static mrb_value mrb_cgroup_attach(mrb_state *mrb, mrb_value self) 166 | { 167 | mrb_cgroup_context *mrb_cg_cxt = mrb_cgroup_get_context(mrb, self, "mrb_cgroup_context"); 168 | mrb_value pid = mrb_nil_value(); 169 | mrb_get_args(mrb, "|i", &pid); 170 | 171 | if (mrb_nil_p(pid)) { 172 | cgroup_attach_task(mrb_cg_cxt->cg); 173 | } else { 174 | cgroup_attach_task_pid(mrb_cg_cxt->cg, mrb_fixnum(pid)); 175 | } 176 | mrb_iv_set(mrb, self, mrb_intern_cstr(mrb, "mrb_cgroup_context"), 177 | mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &mrb_cgroup_context_type, (void *)mrb_cg_cxt))); 178 | 179 | return self; 180 | } 181 | 182 | static mrb_value mrb_cgroup_group_name(mrb_state *mrb, mrb_value self) 183 | { 184 | mrb_cgroup_context *mrb_cg_cxt = mrb_cgroup_get_context(mrb, self, "mrb_cgroup_context"); 185 | if (mrb_cg_cxt) { 186 | return mrb_cg_cxt->group_name; 187 | } else { 188 | return mrb_nil_value(); 189 | } 190 | } 191 | 192 | // 193 | // init 194 | // 195 | #define SET_MRB_CGROUP_INIT_GROUP(gname) \ 196 | static mrb_value mrb_cgroup_##gname##_init(mrb_state *mrb, mrb_value self) \ 197 | { \ 198 | mrb_cgroup_context *mrb_cg_cxt = (mrb_cgroup_context *)mrb_malloc(mrb, sizeof(mrb_cgroup_context)); \ 199 | \ 200 | mrb_cg_cxt->type = MRB_CGROUP_##gname; \ 201 | if (cgroup_init()) { \ 202 | mrb_raise(mrb, E_RUNTIME_ERROR, "cgroup_init " #gname " failed"); \ 203 | } \ 204 | mrb_get_args(mrb, "o", &mrb_cg_cxt->group_name); \ 205 | mrb_cg_cxt->cg = cgroup_new_cgroup(RSTRING_PTR(mrb_cg_cxt->group_name)); \ 206 | if (mrb_cg_cxt->cg == NULL) { \ 207 | mrb_raise(mrb, E_RUNTIME_ERROR, "cgroup_new_cgroup failed"); \ 208 | } \ 209 | \ 210 | if (cgroup_get_cgroup(mrb_cg_cxt->cg)) { \ 211 | mrb_cg_cxt->already_exist = 0; \ 212 | mrb_cg_cxt->cgc = cgroup_add_controller(mrb_cg_cxt->cg, #gname); \ 213 | if (mrb_cg_cxt->cgc == NULL) { \ 214 | mrb_raise(mrb, E_RUNTIME_ERROR, "cgroup_add_controller " #gname " failed"); \ 215 | } \ 216 | } else { \ 217 | mrb_cg_cxt->already_exist = 1; \ 218 | mrb_cg_cxt->cgc = cgroup_get_controller(mrb_cg_cxt->cg, #gname); \ 219 | if (mrb_cg_cxt->cgc == NULL) { \ 220 | mrb_cg_cxt->cgc = cgroup_add_controller(mrb_cg_cxt->cg, #gname); \ 221 | if (mrb_cg_cxt->cgc == NULL) { \ 222 | mrb_raise(mrb, E_RUNTIME_ERROR, "get_cgroup success, but add_controller " #gname " failed"); \ 223 | } \ 224 | } \ 225 | } \ 226 | mrb_iv_set( \ 227 | mrb, self, mrb_intern_cstr(mrb, "mrb_cgroup_context"), \ 228 | mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &mrb_cgroup_context_type, (void *)mrb_cg_cxt))); \ 229 | \ 230 | return self; \ 231 | } 232 | 233 | SET_MRB_CGROUP_INIT_GROUP(cpu); 234 | SET_MRB_CGROUP_INIT_GROUP(cpuset); 235 | SET_MRB_CGROUP_INIT_GROUP(cpuacct); 236 | SET_MRB_CGROUP_INIT_GROUP(blkio); 237 | SET_MRB_CGROUP_INIT_GROUP(memory); 238 | SET_MRB_CGROUP_INIT_GROUP(pids); 239 | 240 | // 241 | // cgroup_set_value_int64 242 | // 243 | #define SET_VALUE_INT64_MRB_CGROUP(gname, key) \ 244 | static mrb_value mrb_cgroup_set_##gname##_##key(mrb_state *mrb, mrb_value self) \ 245 | { \ 246 | mrb_cgroup_context *mrb_cg_cxt = mrb_cgroup_get_context(mrb, self, "mrb_cgroup_context"); \ 247 | mrb_value val; \ 248 | int code; \ 249 | mrb_get_args(mrb, "o", &val); \ 250 | \ 251 | if ((code = cgroup_set_value_int64(mrb_cg_cxt->cgc, #gname "." #key, (int64_t)mrb_to_flo(mrb, val)))) { \ 252 | mrb_raisef(mrb, E_RUNTIME_ERROR, "cgroup_set_value_int64 " #gname "." #key " failed: %S", \ 253 | mrb_str_new_cstr(mrb, cgroup_strerror(code))); \ 254 | } \ 255 | mrb_iv_set( \ 256 | mrb, self, mrb_intern_cstr(mrb, "mrb_cgroup_context"), \ 257 | mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &mrb_cgroup_context_type, (void *)mrb_cg_cxt))); \ 258 | \ 259 | return self; \ 260 | } 261 | 262 | SET_VALUE_INT64_MRB_CGROUP(cpu, cfs_quota_us); 263 | SET_VALUE_INT64_MRB_CGROUP(cpu, cfs_period_us); 264 | SET_VALUE_INT64_MRB_CGROUP(cpu, rt_period_us); 265 | SET_VALUE_INT64_MRB_CGROUP(cpu, rt_runtime_us); 266 | SET_VALUE_INT64_MRB_CGROUP(cpu, shares); 267 | SET_VALUE_INT64_MRB_CGROUP(cpuacct, usage); 268 | SET_VALUE_INT64_MRB_CGROUP(memory, limit_in_bytes); 269 | SET_VALUE_INT64_MRB_CGROUP(pids, max); 270 | 271 | #define GET_VALUE_INT64_MRB_CGROUP(gname, key) \ 272 | static mrb_value mrb_cgroup_get_##gname##_##key(mrb_state *mrb, mrb_value self) \ 273 | { \ 274 | mrb_cgroup_context *mrb_cg_cxt = mrb_cgroup_get_context(mrb, self, "mrb_cgroup_context"); \ 275 | int64_t val; \ 276 | int code; \ 277 | if ((code = cgroup_get_value_int64(mrb_cg_cxt->cgc, #gname "." #key, &val)) && code != ECGROUPVALUENOTEXIST) { \ 278 | mrb_raisef(mrb, E_RUNTIME_ERROR, "cgroup_get_value_int64 " #gname "." #key " failed: %S(%S)", \ 279 | mrb_str_new_cstr(mrb, cgroup_strerror(code)), mrb_fixnum_value(code)); \ 280 | } \ 281 | if (code == ECGROUPVALUENOTEXIST) { \ 282 | return mrb_nil_value(); \ 283 | } else { \ 284 | return mrb_fixnum_value(val); \ 285 | } \ 286 | } 287 | 288 | GET_VALUE_INT64_MRB_CGROUP(cpu, cfs_quota_us); 289 | GET_VALUE_INT64_MRB_CGROUP(cpu, cfs_period_us); 290 | GET_VALUE_INT64_MRB_CGROUP(cpu, rt_period_us); 291 | GET_VALUE_INT64_MRB_CGROUP(cpu, rt_runtime_us); 292 | GET_VALUE_INT64_MRB_CGROUP(cpu, shares); 293 | GET_VALUE_INT64_MRB_CGROUP(cpuacct, usage); 294 | GET_VALUE_INT64_MRB_CGROUP(memory, limit_in_bytes); 295 | GET_VALUE_INT64_MRB_CGROUP(memory, usage_in_bytes); 296 | GET_VALUE_INT64_MRB_CGROUP(memory, max_usage_in_bytes); 297 | GET_VALUE_INT64_MRB_CGROUP(pids, current); 298 | GET_VALUE_INT64_MRB_CGROUP(pids, max); 299 | 300 | // 301 | // cgroup_get_value_string 302 | // 303 | #define GET_VALUE_STRING_MRB_CGROUP(gname, key) \ 304 | static mrb_value mrb_cgroup_get_##gname##_##key(mrb_state *mrb, mrb_value self) \ 305 | { \ 306 | int code; \ 307 | char *val; \ 308 | mrb_cgroup_context *mrb_cg_cxt = mrb_cgroup_get_context(mrb, self, "mrb_cgroup_context"); \ 309 | \ 310 | if ((code = cgroup_get_value_string(mrb_cg_cxt->cgc, #gname "." #key, &val)) != 0 && \ 311 | code != ECGROUPVALUENOTEXIST) { \ 312 | mrb_raisef(mrb, E_RUNTIME_ERROR, "cgroup_get_value_string " #gname "." #key " failed: %S(%S)", \ 313 | mrb_str_new_cstr(mrb, cgroup_strerror(code)), mrb_fixnum_value(code)); \ 314 | } \ 315 | if (code == ECGROUPVALUENOTEXIST || !strcmp(val, "")) { \ 316 | return mrb_nil_value(); \ 317 | } else { \ 318 | return mrb_str_new_cstr(mrb, val); \ 319 | } \ 320 | } 321 | 322 | GET_VALUE_STRING_MRB_CGROUP(cpu, stat); 323 | GET_VALUE_STRING_MRB_CGROUP(cpuset, cpus); 324 | GET_VALUE_STRING_MRB_CGROUP(cpuset, mems); 325 | GET_VALUE_STRING_MRB_CGROUP(cpuacct, stat); 326 | GET_VALUE_STRING_MRB_CGROUP(cpuacct, usage_percpu); 327 | 328 | // 329 | // cgroup_get_value_string (a number of keys are 2) 330 | // 331 | #define GET_VALUE_STRING_MRB_CGROUP_KEY2(gname, key1, key2) \ 332 | static mrb_value mrb_cgroup_get_##gname##_##key1##_##key2(mrb_state *mrb, mrb_value self) \ 333 | { \ 334 | int code; \ 335 | char *val; \ 336 | mrb_cgroup_context *mrb_cg_cxt = mrb_cgroup_get_context(mrb, self, "mrb_cgroup_context"); \ 337 | \ 338 | if ((code = cgroup_get_value_string(mrb_cg_cxt->cgc, #gname "." #key1 "." #key2, &val)) != 0 && \ 339 | code != ECGROUPVALUENOTEXIST) { \ 340 | mrb_raisef(mrb, E_RUNTIME_ERROR, "cgroup_get_value_string " #gname "." #key1 "." #key2 " failed: %S(%S)", \ 341 | mrb_str_new_cstr(mrb, cgroup_strerror(code)), mrb_fixnum_value(code)); \ 342 | } \ 343 | if (code == ECGROUPVALUENOTEXIST || !strcmp(val, "")) { \ 344 | return mrb_nil_value(); \ 345 | } else { \ 346 | return mrb_str_new_cstr(mrb, val); \ 347 | } \ 348 | } 349 | 350 | GET_VALUE_STRING_MRB_CGROUP_KEY2(blkio, throttle, read_bps_device); 351 | GET_VALUE_STRING_MRB_CGROUP_KEY2(blkio, throttle, write_bps_device); 352 | GET_VALUE_STRING_MRB_CGROUP_KEY2(blkio, throttle, read_iops_device); 353 | GET_VALUE_STRING_MRB_CGROUP_KEY2(blkio, throttle, write_iops_device); 354 | 355 | // 356 | // cgroup_get_value_int64 (a number of keys are 2) 357 | // 358 | #define GET_VALUE_INT64_MRB_CGROUP_KEY2(gname, key1, key2) \ 359 | static mrb_value mrb_cgroup_get_##gname##_##key1##_##key2(mrb_state *mrb, mrb_value self) \ 360 | { \ 361 | int code; \ 362 | int64_t val; \ 363 | mrb_cgroup_context *mrb_cg_cxt = mrb_cgroup_get_context(mrb, self, "mrb_cgroup_context"); \ 364 | \ 365 | if ((code = cgroup_get_value_int64(mrb_cg_cxt->cgc, #gname "." #key1 "." #key2, &val)) != 0 && \ 366 | code != ECGROUPVALUENOTEXIST) { \ 367 | mrb_raisef(mrb, E_RUNTIME_ERROR, "cgroup_get_value_int64 " #gname "." #key1 "." #key2 " failed: %S(%S)", \ 368 | mrb_str_new_cstr(mrb, cgroup_strerror(code)), mrb_fixnum_value(code)); \ 369 | } \ 370 | if (code == ECGROUPVALUENOTEXIST) { \ 371 | return mrb_nil_value(); \ 372 | } else { \ 373 | return mrb_fixnum_value(val); \ 374 | } \ 375 | } 376 | 377 | GET_VALUE_INT64_MRB_CGROUP_KEY2(memory, memsw, limit_in_bytes); 378 | GET_VALUE_INT64_MRB_CGROUP_KEY2(memory, memsw, usage_in_bytes); 379 | GET_VALUE_INT64_MRB_CGROUP_KEY2(memory, memsw, max_usage_in_bytes); 380 | 381 | // 382 | // cgroup_set_value_string 383 | // 384 | #define SET_VALUE_STRING_MRB_CGROUP(gname, key) \ 385 | static mrb_value mrb_cgroup_set_##gname##_##key(mrb_state *mrb, mrb_value self) \ 386 | { \ 387 | mrb_cgroup_context *mrb_cg_cxt = mrb_cgroup_get_context(mrb, self, "mrb_cgroup_context"); \ 388 | int code; \ 389 | char *val; \ 390 | mrb_get_args(mrb, "z", &val); \ 391 | if ((code = cgroup_set_value_string(mrb_cg_cxt->cgc, #gname "." #key, val))) { \ 392 | mrb_raisef(mrb, E_RUNTIME_ERROR, "cgroup_set_value_string " #gname "." #key " failed: %S(%S)", \ 393 | mrb_str_new_cstr(mrb, cgroup_strerror(code)), mrb_fixnum_value(code)); \ 394 | } \ 395 | mrb_iv_set( \ 396 | mrb, self, mrb_intern_cstr(mrb, "mrb_cgroup_context"), \ 397 | mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &mrb_cgroup_context_type, (void *)mrb_cg_cxt))); \ 398 | return self; \ 399 | } 400 | 401 | SET_VALUE_STRING_MRB_CGROUP(cpuset, cpus); 402 | SET_VALUE_STRING_MRB_CGROUP(cpuset, mems); 403 | 404 | // 405 | // cgroup_set_value_string (a number of keys are 2) 406 | // 407 | #define SET_VALUE_STRING_MRB_CGROUP_KEY2(gname, key1, key2) \ 408 | static mrb_value mrb_cgroup_set_##gname##_##key1##_##key2(mrb_state *mrb, mrb_value self) \ 409 | { \ 410 | mrb_cgroup_context *mrb_cg_cxt = mrb_cgroup_get_context(mrb, self, "mrb_cgroup_context"); \ 411 | int code; \ 412 | char *val; \ 413 | mrb_get_args(mrb, "z", &val); \ 414 | if ((code = cgroup_set_value_string(mrb_cg_cxt->cgc, #gname "." #key1 "." #key2, val)) != 0) { \ 415 | mrb_raisef(mrb, E_RUNTIME_ERROR, "cgroup_set_value_string " #gname "." #key1 "." #key2 " failed: %S(%S)", \ 416 | mrb_str_new_cstr(mrb, cgroup_strerror(code)), mrb_fixnum_value(code)); \ 417 | } \ 418 | mrb_iv_set( \ 419 | mrb, self, mrb_intern_cstr(mrb, "mrb_cgroup_context"), \ 420 | mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &mrb_cgroup_context_type, (void *)mrb_cg_cxt))); \ 421 | return self; \ 422 | } 423 | 424 | SET_VALUE_STRING_MRB_CGROUP_KEY2(blkio, throttle, read_bps_device); 425 | SET_VALUE_STRING_MRB_CGROUP_KEY2(blkio, throttle, write_bps_device); 426 | SET_VALUE_STRING_MRB_CGROUP_KEY2(blkio, throttle, read_iops_device); 427 | SET_VALUE_STRING_MRB_CGROUP_KEY2(blkio, throttle, write_iops_device); 428 | 429 | // 430 | // cgroup_set_value_int64 (a number of keys are 2) 431 | // 432 | #define SET_VALUE_INT64_CGROUP_KEY2(gname, key1, key2) \ 433 | static mrb_value mrb_cgroup_set_##gname##_##key1##_##key2(mrb_state *mrb, mrb_value self) \ 434 | { \ 435 | mrb_cgroup_context *mrb_cg_cxt = mrb_cgroup_get_context(mrb, self, "mrb_cgroup_context"); \ 436 | int code; \ 437 | mrb_value val; \ 438 | mrb_get_args(mrb, "o", &val); \ 439 | if ((code = cgroup_set_value_int64(mrb_cg_cxt->cgc, #gname "." #key1 "." #key2, mrb_fixnum(val))) != 0) { \ 440 | mrb_raisef(mrb, E_RUNTIME_ERROR, "cgroup_set_value_int64 " #gname "." #key1 "." #key2 " failed: %S(%S)", \ 441 | mrb_str_new_cstr(mrb, cgroup_strerror(code)), mrb_fixnum_value(code)); \ 442 | } \ 443 | mrb_iv_set( \ 444 | mrb, self, mrb_intern_cstr(mrb, "mrb_cgroup_context"), \ 445 | mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &mrb_cgroup_context_type, (void *)mrb_cg_cxt))); \ 446 | return self; \ 447 | } 448 | 449 | SET_VALUE_INT64_CGROUP_KEY2(memory, memsw, limit_in_bytes); 450 | 451 | // 452 | // cgroup_set_value_string (a number of keys are 2) 453 | // 454 | #define SET_VALUE_STRING_MRB_CGROUP_KEY2_NOT_USE_GNAME(gname, key1, key2) \ 455 | static mrb_value mrb_cgroup_set_##gname##_##key1##_##key2(mrb_state *mrb, mrb_value self) \ 456 | { \ 457 | mrb_cgroup_context *mrb_cg_cxt = mrb_cgroup_get_context(mrb, self, "mrb_cgroup_context"); \ 458 | int code; \ 459 | char *val; \ 460 | mrb_get_args(mrb, "z", &val); \ 461 | if ((code = cgroup_set_value_string(mrb_cg_cxt->cgc, #key1 "." #key2, val)) != 0) { \ 462 | mrb_raisef(mrb, E_RUNTIME_ERROR, "cgroup_set_value_string " #key1 "." #key2 " failed: %S(%S)", \ 463 | mrb_str_new_cstr(mrb, cgroup_strerror(code)), mrb_fixnum_value(code)); \ 464 | } \ 465 | mrb_iv_set( \ 466 | mrb, self, mrb_intern_cstr(mrb, "mrb_cgroup_context"), \ 467 | mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &mrb_cgroup_context_type, (void *)mrb_cg_cxt))); \ 468 | return self; \ 469 | } 470 | 471 | SET_VALUE_STRING_MRB_CGROUP_KEY2_NOT_USE_GNAME(memory, cgroup, event_control); 472 | 473 | // 474 | // cgroup_set_bool 475 | // 476 | #define SET_VALUE_BOOL_MRB_CGROUP(gname, key) \ 477 | static mrb_value mrb_cgroup_set_##gname##_##key(mrb_state *mrb, mrb_value self) \ 478 | { \ 479 | mrb_cgroup_context *mrb_cg_cxt = mrb_cgroup_get_context(mrb, self, "mrb_cgroup_context"); \ 480 | mrb_bool val; \ 481 | int code; \ 482 | mrb_get_args(mrb, "b", &val); \ 483 | \ 484 | if ((code = cgroup_set_value_bool(mrb_cg_cxt->cgc, #gname "." #key, (bool)val))) { \ 485 | mrb_raisef(mrb, E_RUNTIME_ERROR, "cgroup_set_value_book " #gname "." #key " failed: %S", \ 486 | mrb_str_new_cstr(mrb, cgroup_strerror(code))); \ 487 | } \ 488 | mrb_iv_set( \ 489 | mrb, self, mrb_intern_cstr(mrb, "mrb_cgroup_context"), \ 490 | mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &mrb_cgroup_context_type, (void *)mrb_cg_cxt))); \ 491 | \ 492 | return self; \ 493 | } 494 | 495 | SET_VALUE_BOOL_MRB_CGROUP(memory, oom_control); 496 | 497 | #define GET_VALUE_BOOL_MRB_CGROUP(gname, key) \ 498 | static mrb_value mrb_cgroup_get_##gname##_##key(mrb_state *mrb, mrb_value self) \ 499 | { \ 500 | mrb_cgroup_context *mrb_cg_cxt = mrb_cgroup_get_context(mrb, self, "mrb_cgroup_context"); \ 501 | bool val; \ 502 | int code; \ 503 | if ((code = cgroup_get_value_bool(mrb_cg_cxt->cgc, #gname "." #key, &val)) && code != ECGROUPVALUENOTEXIST) { \ 504 | mrb_raisef(mrb, E_RUNTIME_ERROR, "cgroup_get_value_bool " #gname "." #key " failed: %S(%S)", \ 505 | mrb_str_new_cstr(mrb, cgroup_strerror(code)), mrb_fixnum_value(code)); \ 506 | } \ 507 | if (code == ECGROUPVALUENOTEXIST) { \ 508 | return mrb_nil_value(); \ 509 | } else { \ 510 | return mrb_bool_value(val); \ 511 | } \ 512 | } 513 | 514 | GET_VALUE_BOOL_MRB_CGROUP(memory, oom_control); 515 | 516 | static mrb_value mrb_cgroup_get_cpuacct_obj(mrb_state *mrb, mrb_value self) 517 | { 518 | mrb_value cpuacct_value; 519 | struct RClass *cpuacct_class, *cgroup_class; 520 | mrb_cgroup_context *mrb_cg_cxt = mrb_cgroup_get_context(mrb, self, "mrb_cgroup_context"); 521 | 522 | cpuacct_value = mrb_iv_get(mrb, self, mrb_intern_cstr(mrb, "cpuacct_obj")); 523 | if (mrb_nil_p(cpuacct_value)) { 524 | cgroup_class = mrb_class_get(mrb, "Cgroup"); 525 | cpuacct_class = (struct RClass *)mrb_class_ptr( 526 | mrb_const_get(mrb, mrb_obj_value(cgroup_class), mrb_intern_cstr(mrb, "CPUACCT"))); 527 | cpuacct_value = mrb_obj_new(mrb, cpuacct_class, 1, &mrb_cg_cxt->group_name); 528 | mrb_iv_set(mrb, self, mrb_intern_cstr(mrb, "cpuacct_obj"), cpuacct_value); 529 | } 530 | return cpuacct_value; 531 | } 532 | 533 | void mrb_mruby_cgroup_gem_init(mrb_state *mrb) 534 | { 535 | struct RClass *cgroup; 536 | struct RClass *cpu; 537 | struct RClass *cpuacct; 538 | struct RClass *cpuset; 539 | struct RClass *blkio; 540 | struct RClass *memory; 541 | struct RClass *pids; 542 | 543 | cgroup = mrb_define_module(mrb, "Cgroup"); 544 | mrb_define_module_function(mrb, cgroup, "create", mrb_cgroup_create, MRB_ARGS_NONE()); 545 | // BUG? cgroup_modify_cgroup fail fclose on cg_set_control_value: line:1389 when get existing cgroup 546 | // controller 547 | // mrb_define_module_function(mrb, cgroup, "modify", mrb_cgroup_modify, MRB_ARGS_NONE()); 548 | mrb_define_module_function(mrb, cgroup, "modify", mrb_cgroup_create, MRB_ARGS_NONE()); 549 | mrb_define_module_function(mrb, cgroup, "open", mrb_cgroup_create, MRB_ARGS_NONE()); 550 | mrb_define_module_function(mrb, cgroup, "delete", mrb_cgroup_delete, MRB_ARGS_NONE()); 551 | mrb_define_module_function(mrb, cgroup, "close", mrb_cgroup_delete, MRB_ARGS_NONE()); 552 | mrb_define_module_function(mrb, cgroup, "attach", mrb_cgroup_attach, MRB_ARGS_OPT(1)); 553 | // mrb_define_module_function(mrb, cgroup, "path", mrb_cgroup_get_current_path, MRB_ARGS_OPT(1)); 554 | mrb_define_module_function(mrb, cgroup, "exist?", mrb_cgroup_exist_p, MRB_ARGS_NONE()); 555 | mrb_define_module_function(mrb, cgroup, "attach", mrb_cgroup_attach, MRB_ARGS_ANY()); 556 | mrb_define_module_function(mrb, cgroup, "group_name", mrb_cgroup_group_name, MRB_ARGS_NONE()); 557 | DONE; 558 | 559 | cpu = mrb_define_class_under(mrb, cgroup, "CPU", mrb->object_class); 560 | mrb_include_module(mrb, cpu, mrb_module_get(mrb, "Cgroup")); 561 | mrb_define_method(mrb, cpu, "initialize", mrb_cgroup_cpu_init, MRB_ARGS_ANY()); 562 | mrb_define_method(mrb, cpu, "cfs_quota_us=", mrb_cgroup_set_cpu_cfs_quota_us, MRB_ARGS_ANY()); 563 | mrb_define_method(mrb, cpu, "cfs_quota_us", mrb_cgroup_get_cpu_cfs_quota_us, MRB_ARGS_NONE()); 564 | mrb_define_method(mrb, cpu, "cfs_period_us=", mrb_cgroup_set_cpu_cfs_period_us, MRB_ARGS_ANY()); 565 | mrb_define_method(mrb, cpu, "cfs_period_us", mrb_cgroup_get_cpu_cfs_period_us, MRB_ARGS_NONE()); 566 | mrb_define_method(mrb, cpu, "rt_period_us=", mrb_cgroup_set_cpu_rt_period_us, MRB_ARGS_ANY()); 567 | mrb_define_method(mrb, cpu, "rt_period_us", mrb_cgroup_get_cpu_rt_period_us, MRB_ARGS_NONE()); 568 | mrb_define_method(mrb, cpu, "rt_runtime_us=", mrb_cgroup_set_cpu_rt_runtime_us, MRB_ARGS_ANY()); 569 | mrb_define_method(mrb, cpu, "rt_runtime_us", mrb_cgroup_get_cpu_rt_runtime_us, MRB_ARGS_NONE()); 570 | mrb_define_method(mrb, cpu, "shares=", mrb_cgroup_set_cpu_shares, MRB_ARGS_ANY()); 571 | mrb_define_method(mrb, cpu, "shares", mrb_cgroup_get_cpu_shares, MRB_ARGS_NONE()); 572 | mrb_define_method(mrb, cpu, "stat", mrb_cgroup_get_cpu_stat, MRB_ARGS_NONE()); 573 | mrb_define_method(mrb, cpu, "cpuacct", mrb_cgroup_get_cpuacct_obj, MRB_ARGS_NONE()); 574 | DONE; 575 | 576 | cpuacct = mrb_define_class_under(mrb, cgroup, "CPUACCT", mrb->object_class); 577 | mrb_include_module(mrb, cpuacct, mrb_module_get(mrb, "Cgroup")); 578 | mrb_define_method(mrb, cpuacct, "initialize", mrb_cgroup_cpuacct_init, MRB_ARGS_REQ(1)); 579 | mrb_define_method(mrb, cpuacct, "stat", mrb_cgroup_get_cpuacct_stat, MRB_ARGS_NONE()); 580 | mrb_define_method(mrb, cpuacct, "usage", mrb_cgroup_get_cpuacct_usage, MRB_ARGS_NONE()); 581 | mrb_define_method(mrb, cpuacct, "usage=", mrb_cgroup_set_cpuacct_usage, MRB_ARGS_REQ(1)); 582 | mrb_define_method(mrb, cpuacct, "usage_percpu", mrb_cgroup_get_cpuacct_usage_percpu, MRB_ARGS_NONE()); 583 | DONE; 584 | 585 | cpuset = mrb_define_class_under(mrb, cgroup, "CPUSET", mrb->object_class); 586 | mrb_include_module(mrb, cpuset, mrb_module_get(mrb, "Cgroup")); 587 | mrb_define_method(mrb, cpuset, "initialize", mrb_cgroup_cpuset_init, MRB_ARGS_ANY()); 588 | mrb_define_method(mrb, cpuset, "cpus=", mrb_cgroup_set_cpuset_cpus, MRB_ARGS_REQ(1)); 589 | mrb_define_method(mrb, cpuset, "cpus", mrb_cgroup_get_cpuset_cpus, MRB_ARGS_NONE()); 590 | mrb_define_method(mrb, cpuset, "mems=", mrb_cgroup_set_cpuset_mems, MRB_ARGS_REQ(1)); 591 | mrb_define_method(mrb, cpuset, "mems", mrb_cgroup_get_cpuset_mems, MRB_ARGS_NONE()); 592 | DONE; 593 | 594 | blkio = mrb_define_class_under(mrb, cgroup, "BLKIO", mrb->object_class); 595 | mrb_include_module(mrb, blkio, mrb_module_get(mrb, "Cgroup")); 596 | mrb_define_method(mrb, blkio, "initialize", mrb_cgroup_blkio_init, MRB_ARGS_ANY()); 597 | mrb_define_method(mrb, blkio, "throttle_read_bps_device=", mrb_cgroup_set_blkio_throttle_read_bps_device, 598 | MRB_ARGS_ANY()); 599 | mrb_define_method(mrb, blkio, "throttle_read_bps_device", mrb_cgroup_get_blkio_throttle_read_bps_device, 600 | MRB_ARGS_NONE()); 601 | mrb_define_method(mrb, blkio, "throttle_write_bps_device=", mrb_cgroup_set_blkio_throttle_write_bps_device, 602 | MRB_ARGS_ANY()); 603 | mrb_define_method(mrb, blkio, "throttle_write_bps_device", mrb_cgroup_get_blkio_throttle_write_bps_device, 604 | MRB_ARGS_ANY()); 605 | mrb_define_method(mrb, blkio, "throttle_read_iops_device=", mrb_cgroup_set_blkio_throttle_read_iops_device, 606 | MRB_ARGS_ANY()); 607 | mrb_define_method(mrb, blkio, "throttle_read_iops_device", mrb_cgroup_get_blkio_throttle_read_iops_device, 608 | MRB_ARGS_NONE()); 609 | mrb_define_method(mrb, blkio, "throttle_write_iops_device=", mrb_cgroup_set_blkio_throttle_write_iops_device, 610 | MRB_ARGS_ANY()); 611 | mrb_define_method(mrb, blkio, "throttle_write_iops_device", mrb_cgroup_get_blkio_throttle_write_iops_device, 612 | MRB_ARGS_NONE()); 613 | DONE; 614 | 615 | memory = mrb_define_class_under(mrb, cgroup, "MEMORY", mrb->object_class); 616 | mrb_include_module(mrb, memory, mrb_module_get(mrb, "Cgroup")); 617 | mrb_define_method(mrb, memory, "initialize", mrb_cgroup_memory_init, MRB_ARGS_ANY()); 618 | mrb_define_method(mrb, memory, "limit_in_bytes=", mrb_cgroup_set_memory_limit_in_bytes, MRB_ARGS_ANY()); 619 | mrb_define_method(mrb, memory, "limit_in_bytes", mrb_cgroup_get_memory_limit_in_bytes, MRB_ARGS_NONE()); 620 | mrb_define_method(mrb, memory, "usage_in_bytes", mrb_cgroup_get_memory_usage_in_bytes, MRB_ARGS_NONE()); 621 | mrb_define_method(mrb, memory, "max_usage_in_bytes", mrb_cgroup_get_memory_max_usage_in_bytes, MRB_ARGS_NONE()); 622 | mrb_define_method(mrb, memory, "cgroup_event_control=", mrb_cgroup_set_memory_cgroup_event_control, MRB_ARGS_ANY()); 623 | mrb_define_method(mrb, memory, "oom_control=", mrb_cgroup_set_memory_oom_control, MRB_ARGS_ANY()); 624 | mrb_define_method(mrb, memory, "oom_control", mrb_cgroup_get_memory_oom_control, MRB_ARGS_NONE()); 625 | mrb_define_method(mrb, memory, "memsw_limit_in_bytes=", mrb_cgroup_set_memory_memsw_limit_in_bytes, MRB_ARGS_ANY()); 626 | mrb_define_method(mrb, memory, "memsw_limit_in_bytes", mrb_cgroup_get_memory_memsw_limit_in_bytes, MRB_ARGS_NONE()); 627 | mrb_define_method(mrb, memory, "memsw_usage_in_bytes", mrb_cgroup_get_memory_memsw_usage_in_bytes, MRB_ARGS_NONE()); 628 | mrb_define_method(mrb, memory, "memsw_max_usage_in_bytes", mrb_cgroup_get_memory_memsw_max_usage_in_bytes, 629 | MRB_ARGS_NONE()); 630 | DONE; 631 | 632 | pids = mrb_define_class_under(mrb, cgroup, "PIDS", mrb->object_class); 633 | mrb_include_module(mrb, pids, mrb_module_get(mrb, "Cgroup")); 634 | mrb_define_method(mrb, pids, "initialize", mrb_cgroup_pids_init, MRB_ARGS_ANY()); 635 | mrb_define_method(mrb, pids, "max=", mrb_cgroup_set_pids_max, MRB_ARGS_REQ(1)); 636 | mrb_define_method(mrb, pids, "max", mrb_cgroup_get_pids_max, MRB_ARGS_NONE()); 637 | mrb_define_method(mrb, pids, "current", mrb_cgroup_get_pids_current, MRB_ARGS_NONE()); 638 | DONE; 639 | } 640 | 641 | void mrb_mruby_cgroup_gem_final(mrb_state *mrb) 642 | { 643 | } 644 | -------------------------------------------------------------------------------- /src/mrb_cgroup.h: -------------------------------------------------------------------------------- 1 | /* 2 | // mrb_cgroups.h - to provide cgroups methods 3 | // 4 | // See Copyright Notice in mrb_cgroups.c 5 | */ 6 | 7 | #ifndef MRB_CGROUPS_H 8 | #define MRB_CGROUPS_H 9 | 10 | void mrb_mruby_cgroups_gem_init(mrb_state *mrb); 11 | 12 | #endif 13 | --------------------------------------------------------------------------------