├── .editorconfig
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── examples
└── basic.cr
├── shard.yml
├── spec
├── iemon_spec.cr
├── objects.cr
├── spec_helper.cr
└── units
│ ├── object.cr
│ ├── primitives.cr
│ └── property.cr
├── src
├── exceptions.cr
├── exceptions
│ └── exceptions.cr
├── iemon.cr
├── lib_shm.cr
├── object.cr
├── object
│ └── object.cr
├── primitives.cr
├── primitives
│ └── primitives.cr
├── property.cr
└── property
│ └── property.cr
└── tools
└── clean.cr
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*.cr]
4 | charset = utf-8
5 | end_of_line = lf
6 | insert_final_newline = true
7 | indent_style = space
8 | indent_size = 2
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /docs/
2 | /lib/
3 | /bin/
4 | /.shards/
5 | *.dwarf
6 |
7 | # Libraries don't need dependency lock
8 | # Dependencies will be locked in application that uses them
9 | /shard.lock
10 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: crystal
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 taicsuzu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | Iemon (伊右衛門)
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Awesome shared object in multiple processes for Crystal
11 |
12 |
13 | ## Abstract
14 |
15 | :star: **This will work!** :star:
16 |
17 | ```crystal
18 | my_object = MyObj.new(x: 1)
19 |
20 | fork do
21 | my_object.x = 2
22 | end
23 |
24 | sleep 0.1
25 |
26 | puts my_object.x
27 | #=> 2
28 | ```
29 |
30 | ## Installation
31 |
32 | Add this to your application's `shard.yml`:
33 |
34 | ```yaml
35 | dependencies:
36 | iemon:
37 | github: tbrand/iemon
38 | ```
39 |
40 | ## Usage
41 |
42 | ```crystal
43 | require "iemon"
44 | ```
45 |
46 | Define your object which inherits `Iemon::Object`.
47 |
48 | Iemon manages shared properties. You can define it by using `assigns` method.
49 | ```crystal
50 | class MyObj < Iemon::Object
51 | assigns(x: Int32)
52 | end
53 | ```
54 |
55 | Then `x` of `MyObj` will be shared between multiple processes.
56 |
57 | So below code will work correctly.
58 | ```crystal
59 | my_obj = MyObj.new(x: 1)
60 |
61 | fork do
62 | my_obj.x = 2
63 | end
64 |
65 | sleep 0.1 # wait a little for a forked process
66 |
67 | puts my_obj.x
68 | #=> 2
69 | ```
70 |
71 | Call `Iemon::Object#clean` once if you don't need to share the properties of the object anymore.
72 |
73 | Otherwise the shared memory remains even if the execution is finished.
74 | ```crystal
75 | my_obj.clean
76 | ```
77 |
78 | If you forget to do that, you can clean all of them by
79 | ```
80 | crystal lib/iemon/tools/clean.cr
81 | ```
82 |
83 | ## Development
84 |
85 | The project is still under the work in progress.
86 |
87 | Any contributions are welcome! :tada:
88 |
89 | ## Contributing
90 |
91 | 1. Fork it ()
92 | 2. Create your feature branch (`git checkout -b my-new-feature`)
93 | 3. Commit your changes (`git commit -am 'Add some feature'`)
94 | 4. Push to the branch (`git push origin my-new-feature`)
95 | 5. Create a new Pull Request
96 |
97 | ## Contributors
98 |
99 | - [tbrand](https://github.com/tbrand) Taichiro Suzuki - creator, maintainer
100 |
--------------------------------------------------------------------------------
/examples/basic.cr:
--------------------------------------------------------------------------------
1 | require "../src/iemon"
2 |
3 | class MyObj < Iemon::Object
4 | assigns(x: Int32)
5 | end
6 |
7 | my_obj = MyObj.new(x: 1)
8 |
9 | fork do
10 | my_obj.x = 2
11 | end
12 |
13 | sleep 0.1
14 |
15 | puts my_obj.x
16 |
17 | my_obj.clean
18 |
--------------------------------------------------------------------------------
/shard.yml:
--------------------------------------------------------------------------------
1 | name: iemon
2 | version: 0.1.0
3 |
4 | authors:
5 | - taicsuzu
6 |
7 | crystal: 0.25.0
8 |
9 | license: MIT
10 |
--------------------------------------------------------------------------------
/spec/iemon_spec.cr:
--------------------------------------------------------------------------------
1 | require "./spec_helper"
2 | require "./units/*"
3 |
--------------------------------------------------------------------------------
/spec/objects.cr:
--------------------------------------------------------------------------------
1 | class X < Iemon::Object
2 | assigns(x: Int32)
3 | end
4 |
5 | class Y
6 | def clean; end
7 | end
8 |
9 | class Z < Iemon::Object
10 | assigns(x: X)
11 | end
12 |
--------------------------------------------------------------------------------
/spec/spec_helper.cr:
--------------------------------------------------------------------------------
1 | require "spec"
2 | require "../src/iemon"
3 | require "./objects"
4 |
--------------------------------------------------------------------------------
/spec/units/object.cr:
--------------------------------------------------------------------------------
1 | describe Iemon::Object do
2 | context "minimum object" do
3 | it "created" do
4 | x = X.new
5 | x.x = 1
6 | x.x.should eq(1)
7 |
8 | x.clean
9 | end
10 |
11 | it "created with default value" do
12 | x = X.new(x: 2)
13 | x.x.should eq(2)
14 |
15 | x.clean
16 | end
17 |
18 | it "change the value from forked process" do
19 | x = X.new(x: 3)
20 |
21 | fork do
22 | x.x = 4
23 | end
24 |
25 | sleep 0.1
26 |
27 | x.x.should eq(4)
28 | x.clean
29 | end
30 |
31 | it "change the value from master process" do
32 | x = X.new(x: 3)
33 |
34 | fork do
35 | sleep 0.1
36 |
37 | x.x.should eq(4)
38 | end
39 |
40 | x.x = 4
41 |
42 | sleep 0.2
43 |
44 | x.clean
45 | end
46 |
47 | it "change the value from forked process on another forked process" do
48 | x = X.new(x: 3)
49 |
50 | fork do
51 | x.x = 4
52 | end
53 |
54 | fork do
55 | sleep 0.1
56 |
57 | x.x.should eq(4)
58 | end
59 |
60 | sleep 0.2
61 |
62 | x.clean
63 | end
64 | end
65 |
66 | context "nested Iemon::Object" do
67 | it "created" do
68 | x = X.new(x: 1)
69 | z = Z.new(x: x)
70 | z.clean(true)
71 | end
72 |
73 | it "change the nested value from forked process" do
74 | x = X.new(x: 1)
75 | z = Z.new(x: x)
76 |
77 | fork do
78 | z.x.x = 2
79 | end
80 |
81 | sleep 0.1
82 |
83 | z.x.x.should eq(2)
84 | z.clean(true)
85 | end
86 |
87 | it "change the nested value from master process" do
88 | x = X.new(x: 1)
89 | z = Z.new(x: x)
90 |
91 | fork do
92 | sleep 0.1
93 |
94 | z.x.x.should eq(2)
95 | end
96 |
97 | z.x.x = 2
98 |
99 | sleep 0.2
100 |
101 | z.clean(true)
102 | end
103 |
104 | it "change the nested value from forked process on another forked process" do
105 | x = X.new(x: 1)
106 | z = Z.new(x: x)
107 |
108 | fork do
109 | z.x.x = 2
110 | end
111 |
112 | fork do
113 | sleep 0.1
114 |
115 | z.x.x.should eq(2)
116 | end
117 |
118 | sleep 0.2
119 |
120 | z.clean(true)
121 | end
122 |
123 | it "change the nested object from forked process" do
124 | x = X.new(x: 1)
125 | z = Z.new(x: x)
126 |
127 | fork do
128 | _x = X.new(x: 2)
129 |
130 | z.x = _x
131 | end
132 |
133 | sleep 0.1
134 |
135 | z.x.x.should eq(2)
136 | z.clean(true)
137 | end
138 |
139 | it "change the nested object from master process" do
140 | x = X.new(x: 1)
141 | z = Z.new(x: x)
142 |
143 | fork do
144 | sleep 0.1
145 |
146 | z.x.x.should eq(2)
147 | end
148 |
149 | _x = X.new(x: 2)
150 | z.x = _x
151 |
152 | sleep 0.2
153 |
154 | z.clean(true)
155 | end
156 |
157 | it "change the nested value from forked process on another forked process" do
158 | x = X.new(x: 1)
159 | z = Z.new(x: x)
160 |
161 | fork do
162 | _x = X.new(x: 2)
163 |
164 | z.x = _x
165 | end
166 |
167 | fork do
168 | sleep 0.1
169 |
170 | z.x.x.should eq(2)
171 | end
172 |
173 | sleep 0.2
174 |
175 | z.clean(true)
176 | end
177 | end
178 | end
179 |
--------------------------------------------------------------------------------
/spec/units/primitives.cr:
--------------------------------------------------------------------------------
1 | macro define_primitive_class
2 | {% for prim in Iemon::Primitives::STRUCT %}
3 | class P_{{ prim.id }} < Iemon::Object
4 | assigns(prim: {{ prim.id }})
5 | end
6 | {% end %}
7 |
8 | {% for prim in Iemon::Primitives::CLASS %}
9 | class P_{{ prim.id }} < Iemon::Object
10 | assigns(prim: {{ prim.id }})
11 | end
12 | {% end %}
13 | end
14 |
15 | macro define_primitive_specs
16 | describe "Primitives" do
17 | {% for prim in Iemon::Primitives::STRUCT %}
18 | context "primitive: {{ prim.id }}" do
19 | it "create" do
20 | p = P_{{ prim.id }}.new
21 | p.clean
22 | end
23 | end
24 | {% end %}
25 |
26 | {% for prim in Iemon::Primitives::CLASS %}
27 | context "primitive: {{ prim.id }}" do
28 | it "create" do
29 | p = P_{{ prim.id }}.new
30 | p.clean
31 | end
32 | end
33 | {% end %}
34 | end
35 | end
36 |
37 | define_primitive_class
38 | define_primitive_specs
39 |
--------------------------------------------------------------------------------
/spec/units/property.cr:
--------------------------------------------------------------------------------
1 | describe Iemon::Property do
2 | context "value" do
3 | it "set and get correctly" do
4 | prop = Iemon::Property(Int32).new
5 | prop.set_value(1)
6 | prop.value.should eq(1)
7 | prop.clean
8 | end
9 |
10 | it "set value in constructor" do
11 | prop = Iemon::Property(Int32).new(1)
12 | prop.value.should eq(1)
13 | prop.clean
14 | end
15 |
16 | it "set_value raises NotSupportedType if it's not" do
17 | prop = Iemon::Property(Y).new
18 |
19 | expect_raises(Iemon::NotSupportedType,
20 | "Y can not be assigned. "+
21 | "Only primitive types or Iemon::Object are supported.") do
22 | prop.set_value(Y.new)
23 | end
24 |
25 | prop.clean
26 | end
27 |
28 | it "value raises NotAttached if it's not" do
29 | prop = Iemon::Property(Int32).new
30 |
31 | expect_raises(Iemon::NotAttached, "Property(Int32) is not attached") do
32 | prop.raw_value
33 | end
34 |
35 | prop.clean
36 | end
37 |
38 | it "value raises ValueNotSet if it's not" do
39 | prop = Iemon::Property(Int32).new
40 | prop.attach
41 |
42 | expect_raises(Iemon::ValueNotSet, "Value is not set for Iemon::Property(Int32)") do
43 | prop.raw_value
44 | end
45 |
46 | prop.clean
47 | end
48 | end
49 |
50 | context "attach" do
51 | it "correctly" do
52 | prop = Iemon::Property(Int32).new(1)
53 | prop.attach
54 | prop.attached?.should be_true
55 | prop.detach
56 | prop.clean
57 | end
58 | end
59 |
60 | context "detach" do
61 | it "correctly" do
62 | prop = Iemon::Property(Int32).new(1)
63 | prop.attach
64 | prop.detach
65 | prop.detached?.should be_true
66 | prop.clean
67 | end
68 |
69 | it "after set_value" do
70 | prop = Iemon::Property(Int32).new(1)
71 | prop.detached?.should be_true
72 | prop.clean
73 | end
74 |
75 | it "detached for innter Iemon::Object" do
76 | obj = X.new(x: 1)
77 |
78 | prop = Iemon::Property(X).new(obj)
79 | prop.value.__x_prop.not_nil!.detached?.should eq(true)
80 | prop.clean(true)
81 | end
82 | end
83 |
84 | context "clean" do
85 | it "correctly" do
86 | prop = Iemon::Property(Int32).new(1)
87 | prop.clean
88 | prop.cleaned?.should be_true
89 | end
90 |
91 | it "recursively" do
92 | obj = X.new(x: 1)
93 |
94 | prop = Iemon::Property(X).new(obj)
95 | prop.clean(true)
96 |
97 | obj.__x_prop.not_nil!.cleaned?.should eq(true)
98 | end
99 |
100 | it "not recursively" do
101 | obj = X.new(x: 1)
102 |
103 | prop = Iemon::Property(X).new(obj)
104 | prop.clean(false)
105 |
106 | obj.__x_prop.not_nil!.cleaned?.should eq(false)
107 | obj.__x_prop.not_nil!.clean
108 | end
109 |
110 | it "raises AlreadyCleaned if it's already cleaned" do
111 | prop = Iemon::Property(Int32).new(1)
112 | prop.clean
113 |
114 | expect_raises(Iemon::AlreadyCleaned, "failed to clean the property. "+
115 | "(property is already cleaned)") do
116 | prop.clean
117 | end
118 | end
119 | end
120 | end
121 |
--------------------------------------------------------------------------------
/src/exceptions.cr:
--------------------------------------------------------------------------------
1 | require "./exceptions/*"
2 |
--------------------------------------------------------------------------------
/src/exceptions/exceptions.cr:
--------------------------------------------------------------------------------
1 | module Iemon
2 | class NotAttached < Exception; end
3 | class AlreadyCleaned < Exception; end
4 | class NotSupportedType < Exception; end
5 | class ValueNotSet < Exception; end
6 | class LibShmException < Exception; end
7 | end
8 |
--------------------------------------------------------------------------------
/src/iemon.cr:
--------------------------------------------------------------------------------
1 | require "./lib_shm"
2 | require "./exceptions"
3 | require "./object"
4 | require "./primitives"
5 | require "./property"
6 |
7 | include Iemon::Primitives
8 | #
9 | # Override primitive types so that they can respond to `detach` and `clean`.
10 | # These method do nothing.
11 | #
12 | define_struct
13 | define_class
14 |
--------------------------------------------------------------------------------
/src/lib_shm.cr:
--------------------------------------------------------------------------------
1 | lib LibShm
2 | IPC_PRIVATE = 0
3 |
4 | IPC_CREATE = 1000
5 | IPC_EXCL = 2000
6 |
7 | IPC_RMID = 0
8 |
9 | fun shmget(key : Int32, size : LibC::SizeT, flag : Int32) : Int32
10 | fun shmat(id : Int32, addr : UInt8*, flag : Int32) : UInt8*
11 | fun shmdt(addr : UInt8*) : Int32
12 | fun shmctl(id : Int32, cmd : Int32, shmid_ds : UInt8*) : Int32
13 | end
14 |
--------------------------------------------------------------------------------
/src/object.cr:
--------------------------------------------------------------------------------
1 | require "./object/*"
2 |
--------------------------------------------------------------------------------
/src/object/object.cr:
--------------------------------------------------------------------------------
1 | module Iemon
2 | class Object
3 | #
4 | # Assign properties for the object.
5 | # ```
6 | # class You
7 | # assigns(x: Int32, y: Int32)
8 | # end
9 | # ```
10 | #
11 | # You can access them like `property` macro.
12 | # ```
13 | # you = You.new
14 | # you.x = 2
15 | # puts you.y
16 | # ```
17 | #
18 | macro assigns(**props)
19 | assigns({{ props }})
20 | end
21 |
22 | #
23 | # Assign properties for the object.
24 | # See above comments for the details.
25 | #
26 | macro assigns(props)
27 | {% for n, t in props %}
28 | assign({{ n.id }}, {{ t.id }})
29 | {% end %}
30 |
31 | #
32 | # Iemon's constructor.
33 | # The object which inherit Iemon have to call this.
34 | # ```
35 | # class You < Iemon
36 | # def initialize
37 | # super
38 | # end
39 | # end
40 | # ```
41 | #
42 | def initialize
43 | {% for n, t in props %}
44 | @{{ n.id }} = Iemon::Property({{ t.id }}).new
45 | {% end %}
46 | end
47 |
48 | #
49 | # Iemon's constructor with default values.
50 | # ```
51 | # class You < Iemon
52 | # assigns(x: Int32, y: Int32)
53 | # end
54 | #
55 | # you = You.new(x: 1, y: 2)
56 | # ```
57 | #
58 | def initialize(
59 | {% for n, t in props %}
60 | {{ n }} : {{ t }},
61 | {% end %}
62 | )
63 | {% for n, t in props %}
64 | @{{ n.id }} = Iemon::Property({{ t.id }}).new({{ n }})
65 | {% end %}
66 | end
67 |
68 | #
69 | # A method for detach shm which attached to the object.
70 | # ```
71 | # you.detach
72 | # ```
73 | #
74 | # Note that this method have to be called in
75 | # every objects in every processes.
76 | # ```
77 | # you1 = You.new
78 | # you2 = You.new
79 | #
80 | # fork do
81 | # you1.x = 0
82 | # you2.x = 1
83 | #
84 | # # detach on forked process
85 | # you1.detach
86 | # you2.detach
87 | # end
88 | #
89 | # # detach on main process
90 | # you1.detach
91 | # you2.detach
92 | # ```
93 | #
94 | def detach
95 | {% for n, t in props %}
96 | @{{ n.id }}.not_nil!.detach
97 | {% end %}
98 | end
99 |
100 | #
101 | # A method for cleaning shm
102 | # Call this method once on main process for each object.
103 | # ```
104 | # you1 = You.new
105 | # you2 = You.new
106 | #
107 | # you1.clean
108 | # you2.clean
109 | # ```
110 | #
111 | def clean(recursive : Bool = false)
112 | {% for n, t in props %}
113 | @{{ n.id }}.not_nil!.clean(recursive)
114 | {% end %}
115 | end
116 |
117 | def copy(other : self)
118 | {% for n, t in props %}
119 | @{{ n.id }}.not_nil!.set_value(other.{{ n.id }})
120 | {% end %}
121 | end
122 | end
123 |
124 | #
125 | # Assign a property.
126 | # The first argument is a name of the property.
127 | # The second argument is the type.
128 | # The type have to be primitive or Iemon object.
129 | #
130 | macro assign(n, t)
131 | @{{ n }} : Iemon::Property({{ t }})?
132 |
133 | def {{ n }} : {{ t }}
134 | unless {{ n }} = @{{ n }}
135 | raise "self.{{ n }} is not initialized"
136 | end
137 |
138 | {{ n }}.value
139 | end
140 |
141 | def {{ n }}=(val : {{ t }}) : {{ t }}
142 | unless {{ n }} = @{{ n }}
143 | @{{ n }} = Iemon::Property({{ t }}).new
144 | end
145 |
146 | if val.is_a?(Iemon::Object)
147 | #
148 | # Copy every properties from val
149 | #
150 | @{{ n }}.not_nil!.value.copy(val)
151 | #
152 | # Clean the served object's properties
153 | #
154 | val.clean
155 | else
156 | @{{ n }}.not_nil!.set_value(val)
157 | end
158 |
159 | @{{ n }}.not_nil!.value
160 | end
161 |
162 | #
163 | # To access raw Iemon::Property(T)
164 | # ```
165 | # prop = you.__x_prop
166 | # ```
167 | #
168 | def __{{ n }}_prop : Iemon::Property({{ t }})?
169 | @{{ n }}
170 | end
171 | end
172 | end
173 | end
174 |
--------------------------------------------------------------------------------
/src/primitives.cr:
--------------------------------------------------------------------------------
1 | require "./primitives/*"
2 |
--------------------------------------------------------------------------------
/src/primitives/primitives.cr:
--------------------------------------------------------------------------------
1 | module Iemon
2 | module Primitives
3 | STRUCT = [
4 | Bool, Char, Symbol,
5 | Int8, Int16, Int32, Int64, Int128,
6 | UInt8, UInt16, UInt32, UInt64, UInt128,
7 | Float32, Float64
8 | ]
9 |
10 | CLASS = [
11 | String,
12 | ]
13 |
14 | macro define_struct
15 | {% for s in STRUCT %}
16 | struct {{ s.id }}
17 | #
18 | # Override or define some method if it's needed
19 | #
20 | def clean; end
21 | end
22 | {% end %}
23 | end
24 |
25 | macro define_class
26 | {% for c in CLASS %}
27 | class {{ c.id }}
28 | #
29 | # Override or define some method if it's needed
30 | #
31 | def clean; end
32 | end
33 | {% end %}
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/src/property.cr:
--------------------------------------------------------------------------------
1 | require "./property/*"
2 |
--------------------------------------------------------------------------------
/src/property/property.cr:
--------------------------------------------------------------------------------
1 | module Iemon
2 | class Property(T)
3 | @shm_addr : Pointer(UInt8) = Pointer(UInt8).null
4 | @shm_id : Int32 = -1
5 | @attached_pid : Int32 = -1
6 | @detached_pid : Int32 = -1
7 | @cleaned : Bool = false
8 | @value_set : Bool = false
9 |
10 | def initialize
11 | setup_shm
12 | end
13 |
14 | def initialize(value : T)
15 | setup_shm
16 | set_value(value)
17 | end
18 |
19 | def check_type(value : T)
20 | if !Iemon::Primitives::STRUCT.includes?(T) &&
21 | !Iemon::Primitives::CLASS.includes?(T) &&
22 | !value.is_a?(Iemon::Object)
23 | error_message =
24 | "#{T.name} can not be assigned. " +
25 | "Only primitive types or Iemon::Object are supported."
26 |
27 | raise NotSupportedType.new(error_message)
28 | end
29 | end
30 |
31 | def setup_shm
32 | @shm_id = LibShm.shmget(
33 | LibShm::IPC_PRIVATE, sizeof(T),
34 | LibShm::IPC_CREATE | LibShm::IPC_EXCL
35 | ) if @shm_id < 0
36 | end
37 |
38 | def value : T
39 | attach unless attached?
40 | v = raw_value
41 | detach
42 | v
43 | end
44 |
45 | def raw_value : T
46 | raise NotAttached.new("#{self.class.name} is not attached.") unless attached?
47 | raise ValueNotSet.new("Value is not set for #{self.class.name}") unless @value_set
48 | @shm_addr.as(T*).value
49 | end
50 |
51 | def set_value(value : T)
52 | check_type(value)
53 |
54 | attach unless attached?
55 | set_raw_value(value)
56 | @value_set = true
57 | detach
58 | end
59 |
60 | def set_raw_value(value : T)
61 | @shm_addr.as(T*).value = value
62 | end
63 |
64 | def attached? : Bool
65 | @attached_pid == Process.pid
66 | end
67 |
68 | def attach
69 | raise AlreadyCleaned.new("failed to attach the property. " +
70 | "(property is already cleaned)") if @cleaned
71 |
72 | @shm_addr = LibShm.shmat(@shm_id, nil, 0)
73 |
74 | @attached_pid = Process.pid
75 | @detached_pid = -1
76 | end
77 |
78 | def detached? : Bool
79 | @detached_pid == Process.pid
80 | end
81 |
82 | def detach
83 | raise AlreadyCleaned.new("failed to detach the property. " +
84 | "(property is already cleaned)") if @cleaned
85 |
86 | res = LibShm.shmdt(@shm_addr)
87 | raise LibShmException.new("LibShm#shmdt returns error code: #{res}.") if res != 0
88 |
89 | @attached_pid = -1
90 | @detached_pid = Process.pid
91 | end
92 |
93 | def clean(recursive : Bool = false)
94 | raise AlreadyCleaned.new("failed to clean the property. " +
95 | "(property is already cleaned)") if @cleaned
96 |
97 | value.clean if recursive && value.is_a?(Iemon::Object)
98 |
99 | @cleaned = true
100 | res = LibShm.shmctl(@shm_id, 0, nil)
101 | raise LibShmException.new("LibShm#shmctl returns error code: #{res}.") if res != 0
102 | end
103 |
104 | def cleaned? : Bool
105 | @cleaned
106 | end
107 | end
108 | end
109 |
--------------------------------------------------------------------------------
/tools/clean.cr:
--------------------------------------------------------------------------------
1 | require "colorize"
2 |
3 | puts "start cleaning shm"
4 | puts
5 |
6 | count = 0
7 |
8 | info = `ipcs -m`.split("\n")
9 | info.each do |i|
10 | if i =~ /^m\s+(\d+)\s.+$/
11 | print ".".colorize.fore(:green)
12 | count += 1
13 |
14 | shm_id = $1
15 |
16 | `ipcrm -m #{shm_id}`
17 | end
18 | end
19 |
20 | puts
21 | puts
22 | puts "```"
23 | puts `ipcs -m`
24 | puts "```"
25 | puts
26 | puts "finished (#{count} of shm are cleaned)"
27 |
--------------------------------------------------------------------------------