line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
2
|
|
|
|
|
|
|
## Apache2 Server Side Include Parser - ~/lib/Apache2/SSI/SharedMem.pm |
3
|
|
|
|
|
|
|
## Version v0.1.0 |
4
|
|
|
|
|
|
|
## Copyright(c) 2021 DEGUEST Pte. Ltd. |
5
|
|
|
|
|
|
|
## Author: Jacques Deguest <jack@deguest.jp> |
6
|
|
|
|
|
|
|
## Created 2021/01/18 |
7
|
|
|
|
|
|
|
## Modified 2021/01/23 |
8
|
|
|
|
|
|
|
## All rights reserved |
9
|
|
|
|
|
|
|
## |
10
|
|
|
|
|
|
|
## This program is free software; you can redistribute it and/or modify it |
11
|
|
|
|
|
|
|
## under the same terms as Perl itself. |
12
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
13
|
|
|
|
|
|
|
package Apache2::SSI::SharedMem; |
14
|
|
|
|
|
|
|
BEGIN |
15
|
|
|
|
|
|
|
{ |
16
|
15
|
|
|
15
|
|
100
|
use strict; |
|
15
|
|
|
|
|
25
|
|
|
15
|
|
|
|
|
558
|
|
17
|
15
|
|
|
15
|
|
91
|
use warnings; |
|
15
|
|
|
|
|
27
|
|
|
15
|
|
|
|
|
362
|
|
18
|
15
|
|
|
15
|
|
70
|
use warnings::register; |
|
15
|
|
|
|
|
23
|
|
|
15
|
|
|
|
|
1443
|
|
19
|
15
|
|
|
15
|
|
81
|
use parent qw( Module::Generic ); |
|
15
|
|
|
|
|
26
|
|
|
15
|
|
|
|
|
72
|
|
20
|
15
|
|
|
15
|
|
774
|
use Config; |
|
15
|
|
|
|
|
25
|
|
|
15
|
|
|
|
|
550
|
|
21
|
15
|
|
|
15
|
|
78
|
use JSON (); |
|
15
|
|
|
|
|
27
|
|
|
15
|
|
|
|
|
278
|
|
22
|
15
|
|
|
15
|
|
68
|
use Nice::Try; |
|
15
|
|
|
|
|
26
|
|
|
15
|
|
|
|
|
118
|
|
23
|
15
|
|
|
15
|
|
16795653
|
use Scalar::Util (); |
|
15
|
|
|
|
|
39
|
|
|
15
|
|
|
|
|
497
|
|
24
|
15
|
|
|
15
|
|
88
|
use constant SHM_BUFSIZ => 65536; |
|
15
|
|
|
|
|
30
|
|
|
15
|
|
|
|
|
1471
|
|
25
|
15
|
|
|
15
|
|
89
|
use constant SEM_LOCKER => 0; |
|
15
|
|
|
|
|
44
|
|
|
15
|
|
|
|
|
660
|
|
26
|
15
|
|
|
15
|
|
84
|
use constant SEM_MARKER => 1; |
|
15
|
|
|
|
|
37
|
|
|
15
|
|
|
|
|
675
|
|
27
|
15
|
|
|
15
|
|
87
|
use constant SHM_LOCK_WAIT => 0; |
|
15
|
|
|
|
|
28
|
|
|
15
|
|
|
|
|
643
|
|
28
|
15
|
|
|
15
|
|
79
|
use constant SHM_LOCK_EX => 1; |
|
15
|
|
|
|
|
33
|
|
|
15
|
|
|
|
|
672
|
|
29
|
15
|
|
|
15
|
|
94
|
use constant SHM_LOCK_UN => -1; |
|
15
|
|
|
|
|
28
|
|
|
15
|
|
|
|
|
615
|
|
30
|
15
|
|
|
15
|
|
82
|
use constant SHM_EXISTS => 1; |
|
15
|
|
|
|
|
26
|
|
|
15
|
|
|
|
|
611
|
|
31
|
15
|
|
|
15
|
|
77
|
use constant LOCK_SH => 1; |
|
15
|
|
|
|
|
26
|
|
|
15
|
|
|
|
|
565
|
|
32
|
15
|
|
|
15
|
|
70
|
use constant LOCK_EX => 2; |
|
15
|
|
|
|
|
44
|
|
|
15
|
|
|
|
|
566
|
|
33
|
15
|
|
|
15
|
|
127
|
use constant LOCK_NB => 4; |
|
15
|
|
|
|
|
32
|
|
|
15
|
|
|
|
|
586
|
|
34
|
15
|
|
|
15
|
|
88
|
use constant LOCK_UN => 8; |
|
15
|
|
|
|
|
30
|
|
|
15
|
|
|
|
|
5703
|
|
35
|
|
|
|
|
|
|
## if( $^O =~ /^(?:Android|cygwin|dos|MSWin32|os2|VMS|riscos)/ ) |
36
|
|
|
|
|
|
|
## Even better |
37
|
15
|
|
|
15
|
|
107
|
our $SUPPORTED_RE = qr/\bIPC\/SysV\b/m; |
38
|
15
|
50
|
33
|
|
|
1870
|
if( $Config{extensions} =~ m/$SUPPORTED_RE/ && |
|
|
|
33
|
|
|
|
|
39
|
|
|
|
|
|
|
## No support for threads |
40
|
|
|
|
|
|
|
!$Config{useithreads} && |
41
|
|
|
|
|
|
|
$^O !~ /^(?:Android|cygwin|dos|MSWin32|os2|VMS|riscos)/i ) |
42
|
|
|
|
|
|
|
{ |
43
|
15
|
|
|
|
|
10499
|
require IPC::SysV; |
44
|
15
|
|
|
|
|
20950
|
IPC::SysV->import( qw( IPC_RMID IPC_PRIVATE IPC_SET IPC_STAT IPC_CREAT IPC_EXCL IPC_NOWAIT |
45
|
|
|
|
|
|
|
SEM_UNDO S_IRWXU S_IRWXG S_IRWXO |
46
|
|
|
|
|
|
|
GETNCNT GETZCNT GETVAL SETVAL GETPID GETALL SETALL |
47
|
|
|
|
|
|
|
shmat shmdt memread memwrite ftok ) ); |
48
|
15
|
|
|
|
|
44
|
our $SYSV_SUPPORTED = 1; |
49
|
15
|
|
|
|
|
2243
|
eval( <<'EOT' ); |
50
|
|
|
|
|
|
|
our $SEMOP_ARGS = |
51
|
|
|
|
|
|
|
{ |
52
|
|
|
|
|
|
|
(LOCK_EX) => |
53
|
|
|
|
|
|
|
[ |
54
|
|
|
|
|
|
|
1, 0, 0, # wait for readers to finish |
55
|
|
|
|
|
|
|
2, 0, 0, # wait for writers to finish |
56
|
|
|
|
|
|
|
2, 1, SEM_UNDO, # assert write lock |
57
|
|
|
|
|
|
|
], |
58
|
|
|
|
|
|
|
(LOCK_EX | LOCK_NB) => |
59
|
|
|
|
|
|
|
[ |
60
|
|
|
|
|
|
|
1, 0, IPC_NOWAIT, # wait for readers to finish |
61
|
|
|
|
|
|
|
2, 0, IPC_NOWAIT, # wait for writers to finish |
62
|
|
|
|
|
|
|
2, 1, (SEM_UNDO | IPC_NOWAIT), # assert write lock |
63
|
|
|
|
|
|
|
], |
64
|
|
|
|
|
|
|
(LOCK_EX | LOCK_UN) => |
65
|
|
|
|
|
|
|
[ |
66
|
|
|
|
|
|
|
2, -1, (SEM_UNDO | IPC_NOWAIT), |
67
|
|
|
|
|
|
|
], |
68
|
|
|
|
|
|
|
(LOCK_SH) => |
69
|
|
|
|
|
|
|
[ |
70
|
|
|
|
|
|
|
2, 0, 0, # wait for writers to finish |
71
|
|
|
|
|
|
|
1, 1, SEM_UNDO, # assert shared read lock |
72
|
|
|
|
|
|
|
], |
73
|
|
|
|
|
|
|
(LOCK_SH | LOCK_NB) => |
74
|
|
|
|
|
|
|
[ |
75
|
|
|
|
|
|
|
2, 0, IPC_NOWAIT, # wait for writers to finish |
76
|
|
|
|
|
|
|
1, 1, (SEM_UNDO | IPC_NOWAIT), # assert shared read lock |
77
|
|
|
|
|
|
|
], |
78
|
|
|
|
|
|
|
(LOCK_SH | LOCK_UN) => |
79
|
|
|
|
|
|
|
[ |
80
|
|
|
|
|
|
|
1, -1, (SEM_UNDO | IPC_NOWAIT), # remove shared read lock |
81
|
|
|
|
|
|
|
], |
82
|
|
|
|
|
|
|
}; |
83
|
|
|
|
|
|
|
EOT |
84
|
15
|
50
|
|
|
|
1248
|
if( $@ ) |
85
|
|
|
|
|
|
|
{ |
86
|
0
|
|
|
|
|
0
|
warn( "Error while trying to evel \$SEMOP_ARGS: $@\n" ); |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
else |
90
|
|
|
|
|
|
|
{ |
91
|
0
|
|
|
|
|
0
|
our $SYSV_SUPPORTED = 0; |
92
|
|
|
|
|
|
|
} |
93
|
15
|
|
|
|
|
85
|
our @EXPORT_OK = qw(LOCK_EX LOCK_SH LOCK_NB LOCK_UN); |
94
|
15
|
|
|
|
|
98
|
our %EXPORT_TAGS = ( |
95
|
|
|
|
|
|
|
all => [qw( LOCK_EX LOCK_SH LOCK_NB LOCK_UN )], |
96
|
|
|
|
|
|
|
lock => [qw( LOCK_EX LOCK_SH LOCK_NB LOCK_UN )], |
97
|
|
|
|
|
|
|
'flock' => [qw( LOCK_EX LOCK_SH LOCK_NB LOCK_UN )], |
98
|
|
|
|
|
|
|
); |
99
|
|
|
|
|
|
|
# Credits IPC::Shareable |
100
|
15
|
50
|
|
|
|
32
|
our $N = do { my $foo = eval { pack "L!", 0 }; $@ ? '' : '!' }; |
|
15
|
|
|
|
|
27
|
|
|
15
|
|
|
|
|
46
|
|
|
15
|
|
|
|
|
57
|
|
101
|
15
|
|
|
|
|
32
|
our $SHEM_REPO = {}; |
102
|
15
|
|
|
|
|
13075
|
our $VERSION = 'v0.1.0'; |
103
|
|
|
|
|
|
|
}; |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
sub init |
106
|
|
|
|
|
|
|
{ |
107
|
128
|
|
|
128
|
1
|
4475
|
my $self = shift( @_ ); |
108
|
|
|
|
|
|
|
## Default action when accessing a shared memory? If 1, it will create it if it does not exist already |
109
|
128
|
|
|
|
|
950
|
$self->{create} = 0; |
110
|
128
|
|
|
|
|
236
|
$self->{destroy} = 0; |
111
|
128
|
|
|
|
|
211
|
$self->{exclusive} = 0; |
112
|
128
|
|
|
|
|
579
|
$self->{key} = IPC_PRIVATE; |
113
|
128
|
|
|
|
|
1322
|
$self->{mode} = 0666; |
114
|
128
|
|
|
|
|
378
|
$self->{serial} = ''; |
115
|
|
|
|
|
|
|
## SHM_BUFSIZ |
116
|
128
|
|
|
|
|
261
|
$self->{size} = SHM_BUFSIZ; |
117
|
128
|
|
|
|
|
347
|
$self->{_init_strict_use_sub} = 1; |
118
|
128
|
50
|
|
|
|
505
|
$self->SUPER::init( @_ ) || return; |
119
|
128
|
|
|
|
|
4697
|
$self->{addr} = undef(); |
120
|
128
|
|
|
|
|
276
|
$self->{id} = undef(); |
121
|
128
|
|
|
|
|
253
|
$self->{locked} = 0; |
122
|
128
|
|
|
|
|
456
|
$self->{owner} = $$; |
123
|
128
|
|
|
|
|
220
|
$self->{removed} = 0; |
124
|
128
|
|
|
|
|
215
|
$self->{semid} = undef(); |
125
|
128
|
|
|
|
|
595
|
return( $self ); |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
20
|
|
|
20
|
1
|
65
|
sub addr { return( shift->_set_get_scalar( 'addr', @_ ) ); } |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
sub attach |
131
|
|
|
|
|
|
|
{ |
132
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
133
|
0
|
|
|
|
|
0
|
my $flags = shift( @_ ); |
134
|
0
|
0
|
|
|
|
0
|
$flags = $self->flags if( !defined( $flags ) ); |
135
|
0
|
|
|
|
|
0
|
my $addr = $self->addr; |
136
|
0
|
0
|
|
|
|
0
|
return( $addr ) if( defined( $addr ) ); |
137
|
0
|
|
|
|
|
0
|
my $id = $self->id; |
138
|
0
|
0
|
|
|
|
0
|
return( $self->error( "No shared memory id! Have you opened it first?" ) ) if( !length( $id ) ); |
139
|
0
|
|
|
|
|
0
|
$addr = shmat( $id, undef(), $flags ); |
140
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Unable to attach to shared memory: $!" ) ) if( !defined( $addr ) ); |
141
|
0
|
|
|
|
|
0
|
$self->addr( $addr ); |
142
|
0
|
|
|
|
|
0
|
return( $addr ); |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
196
|
|
|
196
|
1
|
3092
|
sub create { return( shift->_set_get_boolean( 'create', @_ ) ); } |
146
|
|
|
|
|
|
|
|
147
|
21
|
|
|
21
|
1
|
130
|
sub destroy { return( shift->_set_get_boolean( 'destroy', @_ ) ); } |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub detach |
150
|
|
|
|
|
|
|
{ |
151
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
152
|
0
|
|
|
|
|
0
|
my $addr = $self->addr; |
153
|
0
|
0
|
|
|
|
0
|
return if( !defined( $addr ) ); |
154
|
0
|
|
|
|
|
0
|
my $rv = shmdt( $addr ); |
155
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Unable to detach from shared memory: $!" ) ) if( !defined( $rv ) ); |
156
|
0
|
|
|
|
|
0
|
$self->addr( undef() ); |
157
|
0
|
|
|
|
|
0
|
return( $self ); |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
130
|
|
|
130
|
1
|
348
|
sub exclusive { return( shift->_set_get_boolean( 'exclusive', @_ ) ); } |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
sub exists |
163
|
|
|
|
|
|
|
{ |
164
|
2
|
|
|
2
|
1
|
295
|
my $self = shift( @_ ); |
165
|
2
|
|
|
|
|
18
|
my $opts = {}; |
166
|
2
|
50
|
|
|
|
11
|
if( ref( $_[0] ) eq 'HASH' ) |
167
|
|
|
|
|
|
|
{ |
168
|
0
|
|
|
|
|
0
|
$opts = shift( @_ ); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
else |
171
|
|
|
|
|
|
|
{ |
172
|
2
|
|
|
|
|
23
|
@$opts{ qw( key mode size ) } = @_; |
173
|
|
|
|
|
|
|
} |
174
|
2
|
50
|
|
|
|
23
|
$opts->{size} = $self->size unless( length( $opts->{size} ) ); |
175
|
2
|
|
|
|
|
51
|
$opts->{size} = int( $opts->{size} ); |
176
|
2
|
|
|
|
|
4
|
my $serial; |
177
|
2
|
50
|
|
|
|
7
|
if( length( $opts->{key} ) ) |
178
|
|
|
|
|
|
|
{ |
179
|
0
|
|
|
|
|
0
|
$serial = $self->_str2key( $opts->{key} ); |
180
|
|
|
|
|
|
|
## $serial = $opts->{key}; |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
else |
183
|
|
|
|
|
|
|
{ |
184
|
2
|
|
|
|
|
7
|
$serial = $self->serial; |
185
|
|
|
|
|
|
|
## $serial = $self->key; |
186
|
|
|
|
|
|
|
} |
187
|
2
|
|
|
|
|
48
|
my $flags = $self->flags({ mode => 0644 }); |
188
|
|
|
|
|
|
|
# Remove the create bit |
189
|
2
|
|
|
|
|
15
|
$flags = ( $flags ^ IPC_CREAT ); |
190
|
|
|
|
|
|
|
## $self->message( 3, "Checking if shared memory key \"", ( $opts->{key} || $self->key ), "\" exists with flags '$flags'." ); |
191
|
2
|
|
|
|
|
8
|
my $semid; |
192
|
2
|
|
|
|
|
3
|
try |
193
|
2
|
|
|
2
|
|
5
|
{ |
194
|
2
|
|
|
|
|
31
|
$semid = semget( $serial, 3, $flags ); |
195
|
|
|
|
|
|
|
## $self->message( 3, "Found the shared memory? ", defined( $semid ) ? 'yes' : 'no' ); |
196
|
2
|
100
|
|
|
|
14
|
if( defined( $semid ) ) |
197
|
|
|
|
|
|
|
{ |
198
|
1
|
|
|
|
|
7
|
my $found = semctl( $semid, SEM_MARKER, GETVAL, 0 ); |
199
|
1
|
|
|
|
|
17
|
semctl( $semid, 0, IPC_RMID, 0 ); |
200
|
1
|
50
|
|
|
|
17
|
return( $found == SHM_EXISTS ? 1 : 0 ); |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
else |
203
|
|
|
|
|
|
|
{ |
204
|
|
|
|
|
|
|
## $self->message( 3, "Error getting a semaphore: $!" ); |
205
|
1
|
50
|
|
|
|
20
|
return( 0 ) if( $! =~ /\bNo[[:blank:]]+such[[:blank:]]+file\b/ ); |
206
|
0
|
|
|
|
|
0
|
return; |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
} |
209
|
2
|
50
|
|
|
|
20
|
catch( $e ) |
|
0
|
50
|
|
|
|
0
|
|
|
2
|
50
|
|
|
|
8
|
|
|
2
|
0
|
|
|
|
2
|
|
|
2
|
50
|
|
|
|
4
|
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
10
|
|
|
0
|
|
|
|
|
0
|
|
|
2
|
|
|
|
|
4
|
|
|
0
|
|
|
|
|
0
|
|
|
2
|
|
|
|
|
8
|
|
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
10
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
210
|
0
|
|
|
0
|
|
0
|
{ |
211
|
|
|
|
|
|
|
## $self->message( 3, "Trying to access shared memory triggered error: $e" ); |
212
|
0
|
0
|
|
|
|
0
|
semctl( $semid, 0, IPC_RMID, 0 ) if( $semid ); |
213
|
0
|
|
|
|
|
0
|
return( 0 ); |
214
|
0
|
0
|
33
|
|
|
0
|
} |
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
2
|
|
|
|
|
26
|
|
|
2
|
|
|
|
|
31
|
|
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
sub flags |
218
|
|
|
|
|
|
|
{ |
219
|
130
|
|
|
130
|
1
|
248
|
my $self = shift( @_ ); |
220
|
130
|
|
|
|
|
226
|
my $opts = {}; |
221
|
15
|
|
|
15
|
|
141
|
no warnings 'uninitialized'; |
|
15
|
|
|
|
|
29
|
|
|
15
|
|
|
|
|
3009
|
|
222
|
130
|
100
|
|
|
|
819
|
$opts = Scalar::Util::reftype( $_[0] ) eq 'HASH' |
|
|
100
|
|
|
|
|
|
223
|
|
|
|
|
|
|
? shift( @_ ) |
224
|
|
|
|
|
|
|
: !( scalar( @_ ) % 2 ) |
225
|
|
|
|
|
|
|
? { @_ } |
226
|
|
|
|
|
|
|
: {}; |
227
|
|
|
|
|
|
|
## $self->message( 3, "Option mode value is '$opts->{mode}'." ); |
228
|
130
|
100
|
|
|
|
563
|
$opts->{create} = $self->create unless( length( $opts->{create} ) ); |
229
|
130
|
50
|
|
|
|
2200
|
$opts->{exclusive} = $self->exclusive unless( length( $opts->{exclusive} ) ); |
230
|
130
|
100
|
|
|
|
3044
|
$opts->{mode} = $self->mode unless( length( $opts->{mode} ) ); |
231
|
130
|
|
|
|
|
1771
|
my $flags = 0; |
232
|
|
|
|
|
|
|
## $self->message( 3, "Adding create bit" ) if( $opts->{create} ); |
233
|
130
|
100
|
|
|
|
365
|
$flags |= IPC_CREAT if( $opts->{create} ); |
234
|
|
|
|
|
|
|
## $self->message( 3, "Adding exclusive bit" ) if( $opts->{exclusive} ); |
235
|
130
|
50
|
|
|
|
1771
|
$flags |= IPC_EXCL if( $opts->{exclusive} ); |
236
|
|
|
|
|
|
|
## $self->message( 3, "Adding mode '", ( $opts->{mode} || 0666 ), "'" ); |
237
|
130
|
|
50
|
|
|
1142
|
$flags |= ( $opts->{mode} || 0666 ); |
238
|
|
|
|
|
|
|
## $self->message( 3, "Returning flags value '$flags'." ); |
239
|
130
|
|
|
|
|
313
|
return( $flags ); |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
## sub id { return( shift->_set_get_scalar( 'id', @_ ) ); } |
243
|
|
|
|
|
|
|
sub id |
244
|
|
|
|
|
|
|
{ |
245
|
89
|
|
|
89
|
1
|
754
|
my $self = shift( @_ ); |
246
|
89
|
|
|
|
|
403
|
my @callinfo = caller; |
247
|
15
|
|
|
15
|
|
112
|
no warnings 'uninitialized'; |
|
15
|
|
|
|
|
31
|
|
|
15
|
|
|
|
|
47750
|
|
248
|
|
|
|
|
|
|
## $self->message( 3, "Called from package $callinfo[0] in file $callinfo[1] at line $callinfo[2] with ", scalar( @_ ) ? ( "args: '" . join( "', '", @_ ) . "'." ) : 'no argument.' ); |
249
|
89
|
100
|
|
|
|
278
|
if( @_ ) |
250
|
|
|
|
|
|
|
{ |
251
|
|
|
|
|
|
|
## $self->message( 3, "Setting id to value '", defined( $_[0] ) ? $_[0] : 'undef()', "'." ); |
252
|
66
|
|
|
|
|
164
|
$self->{id} = shift( @_ ); |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
## $self->message( 3, "Returning id '$self->{id}'" ); |
255
|
89
|
|
|
|
|
238
|
return( $self->{id} ); |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
sub key |
259
|
|
|
|
|
|
|
{ |
260
|
192
|
|
|
192
|
1
|
13192
|
my $self = shift( @_ ); |
261
|
192
|
100
|
|
|
|
479
|
if( @_ ) |
262
|
|
|
|
|
|
|
{ |
263
|
128
|
|
|
|
|
250
|
$self->{key} = shift( @_ ); |
264
|
128
|
|
|
|
|
417
|
$self->{serial} = $self->_str2key( $self->{key} ); |
265
|
|
|
|
|
|
|
## $self->message( 3, "Setting key to '$self->{key}' ($self->{serial})" ); |
266
|
|
|
|
|
|
|
} |
267
|
192
|
|
|
|
|
756
|
return( $self->{key} ); |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
sub lock |
271
|
|
|
|
|
|
|
{ |
272
|
6
|
|
|
6
|
1
|
778
|
my $self = shift( @_ ); |
273
|
6
|
|
|
|
|
29
|
my $type = shift( @_ ); |
274
|
6
|
|
|
|
|
18
|
my $timeout = shift( @_ ); |
275
|
|
|
|
|
|
|
# $type = LOCK_EX if( !defined( $type ) ); |
276
|
6
|
100
|
|
|
|
32
|
$type = LOCK_SH if( !defined( $type ) ); |
277
|
6
|
50
|
|
|
|
72
|
return( $self->unlock ) if( ( $type & LOCK_UN ) ); |
278
|
6
|
50
|
|
|
|
35
|
return( 1 ) if( $self->locked & $type ); |
279
|
6
|
50
|
33
|
|
|
148
|
$timeout = 0 if( !defined( $timeout ) || $timeout !~ /^\d+$/ ); |
280
|
|
|
|
|
|
|
## If the lock is different, release it first |
281
|
6
|
50
|
|
|
|
23
|
$self->unlock if( $self->locked ); |
282
|
6
|
|
50
|
|
|
130
|
my $semid = $self->semid || |
283
|
|
|
|
|
|
|
return( $self->error( "No semaphore id set yet." ) ); |
284
|
|
|
|
|
|
|
## $self->message( 3, "Setting a lock on semaphore id \"$semid\" with type \"$type\" and arguments: ", sub{ $self->dump( $SEMOP_ARGS->{ $type } ) } ); |
285
|
6
|
|
|
|
|
98
|
try |
286
|
6
|
|
|
6
|
|
17
|
{ |
287
|
6
|
|
|
|
|
201
|
local $SIG{ALRM} = sub{ die( "timeout" ); }; |
|
0
|
|
|
|
|
0
|
|
288
|
6
|
|
|
|
|
59
|
alarm( $timeout ); |
289
|
6
|
|
|
|
|
23
|
my $rc = $self->op( @{$SEMOP_ARGS->{ $type }} ); |
|
6
|
|
|
|
|
75
|
|
290
|
6
|
|
|
|
|
36
|
alarm( 0 ); |
291
|
6
|
50
|
|
|
|
36
|
if( $rc ) |
292
|
|
|
|
|
|
|
{ |
293
|
6
|
|
|
|
|
34
|
$self->locked( $type ); |
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
else |
296
|
|
|
|
|
|
|
{ |
297
|
|
|
|
|
|
|
## $self->message( 3, "Unable to set a lock on semaphore id \"$semid\": $!" ); |
298
|
0
|
|
|
|
|
0
|
return( $self->error( "Failed to set a lock on semaphore id \"$semid\": $!" ) ); |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
} |
301
|
6
|
50
|
|
|
|
64
|
catch( $e ) |
|
6
|
50
|
|
|
|
244
|
|
|
6
|
50
|
|
|
|
21
|
|
|
6
|
0
|
|
|
|
19
|
|
|
6
|
50
|
|
|
|
18
|
|
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
11
|
|
|
6
|
|
|
|
|
11
|
|
|
6
|
|
|
|
|
53
|
|
|
0
|
|
|
|
|
0
|
|
|
6
|
|
|
|
|
19
|
|
|
0
|
|
|
|
|
0
|
|
|
6
|
|
|
|
|
40
|
|
|
6
|
|
|
|
|
20
|
|
|
6
|
|
|
|
|
20
|
|
|
6
|
|
|
|
|
28
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
302
|
0
|
|
|
0
|
|
0
|
{ |
303
|
0
|
|
|
|
|
0
|
return( $self->error( "Unable to set a lock: $e" ) ); |
304
|
0
|
0
|
33
|
|
|
0
|
} |
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
6
|
|
|
|
|
186
|
|
|
0
|
|
|
|
|
0
|
|
305
|
6
|
|
|
|
|
50
|
return( $self ); |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
49
|
|
|
49
|
1
|
188
|
sub locked { return( shift->_set_get_scalar( 'locked', @_ ) ); } |
309
|
|
|
|
|
|
|
|
310
|
257
|
|
|
257
|
1
|
2749
|
sub mode { return( shift->_set_get_scalar( 'mode', @_ ) ); } |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub op |
313
|
|
|
|
|
|
|
{ |
314
|
140
|
|
|
140
|
1
|
254
|
my $self = shift( @_ ); |
315
|
140
|
50
|
|
|
|
409
|
return( $self->error( "Invalid number of argument: '", join( ', ', @_ ), "'." ) ) if( @_ % 3 ); |
316
|
140
|
|
|
|
|
696
|
my $data = pack( "s$N*", @_ ); |
317
|
140
|
|
|
|
|
297
|
my $id = $self->semid; |
318
|
140
|
50
|
|
|
|
2149
|
return( $self->error( "No semaphore set yet. You must open the shared memory first to set the semaphore." ) ) if( !length( $id ) ); |
319
|
140
|
|
|
|
|
1167
|
return( semop( $id, $data ) ); |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
sub open |
323
|
|
|
|
|
|
|
{ |
324
|
64
|
|
|
64
|
1
|
450
|
my $self = shift( @_ ); |
325
|
64
|
|
|
|
|
370
|
my $opts = {}; |
326
|
64
|
50
|
|
|
|
230
|
if( ref( $_[0] ) eq 'HASH' ) |
327
|
|
|
|
|
|
|
{ |
328
|
0
|
|
|
|
|
0
|
$opts = shift( @_ ); |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
else |
331
|
|
|
|
|
|
|
{ |
332
|
64
|
|
|
|
|
289
|
@$opts{ qw( key mode size ) } = @_; |
333
|
|
|
|
|
|
|
} |
334
|
64
|
50
|
|
|
|
301
|
$opts->{size} = $self->size unless( length( $opts->{size} ) ); |
335
|
64
|
|
|
|
|
1033
|
$opts->{size} = int( $opts->{size} ); |
336
|
64
|
|
50
|
|
|
545
|
$opts->{mode} //= ''; |
337
|
64
|
|
50
|
|
|
336
|
$opts->{key} //= ''; |
338
|
64
|
|
|
|
|
104
|
my $serial; |
339
|
64
|
50
|
|
|
|
505
|
if( length( $opts->{key} ) ) |
340
|
|
|
|
|
|
|
{ |
341
|
0
|
|
|
|
|
0
|
$serial = $self->_str2key( $opts->{key} ); |
342
|
|
|
|
|
|
|
## $serial = $opts->{key}; |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
else |
345
|
|
|
|
|
|
|
{ |
346
|
64
|
|
|
|
|
233
|
$serial = $self->serial; |
347
|
|
|
|
|
|
|
## $serial = $self->key; |
348
|
|
|
|
|
|
|
} |
349
|
64
|
|
|
|
|
923
|
my $create = 0; |
350
|
64
|
50
|
33
|
|
|
1307
|
if( $opts->{mode} eq 'w' || $opts->{key} =~ s/^>// ) |
|
|
50
|
33
|
|
|
|
|
351
|
|
|
|
|
|
|
{ |
352
|
0
|
|
|
|
|
0
|
$create++; |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
elsif( $opts->{mode} eq 'r' || $opts->{key} =~ s/^<// ) |
355
|
|
|
|
|
|
|
{ |
356
|
0
|
|
|
|
|
0
|
$create = 0; |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
else |
359
|
|
|
|
|
|
|
{ |
360
|
64
|
|
|
|
|
165
|
$create = $self->create; |
361
|
|
|
|
|
|
|
} |
362
|
64
|
|
|
|
|
1645
|
my $flags = $self->flags( create => $create ); |
363
|
|
|
|
|
|
|
## $self->message( 3, "Trying to get the shared memory segment with key '", ( $opts->{key} || $self->key ), "' with serial '$serial', size '$opts->{size}' and mode '$opts->{mode}'." ); |
364
|
64
|
|
|
|
|
868
|
my $id = shmget( $serial, $opts->{size}, $flags ); |
365
|
64
|
50
|
|
|
|
274
|
if( defined( $id ) ) |
366
|
|
|
|
|
|
|
{ |
367
|
|
|
|
|
|
|
## $self->message( 3, "Got the shared memory first time around with id \"$id\"." ); |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
else |
370
|
|
|
|
|
|
|
{ |
371
|
|
|
|
|
|
|
## $self->message( 3, "Shared memory does not exists yet ($!), trying to create it now start from $serial" ); |
372
|
0
|
0
|
|
|
|
0
|
my $newflags = ( $flags & IPC_CREAT ) ? $flags : ( $flags | IPC_CREAT ); |
373
|
0
|
|
|
|
|
0
|
my $limit = ( $serial + 10 ); |
374
|
|
|
|
|
|
|
## IPC::SysV::ftok has likely made the serial unique, but as stated in the manual page, there is no guarantee |
375
|
0
|
|
|
|
|
0
|
while( ++$serial <= $limit ) |
376
|
|
|
|
|
|
|
{ |
377
|
0
|
|
|
|
|
0
|
$id = shmget( $serial, $opts->{size}, $newflags | IPC_CREAT ); |
378
|
|
|
|
|
|
|
## $self->message( 3, "Shared memory key '$serial' worked ? ", defined( $serial ) ? 'yes' : 'no' ); |
379
|
0
|
0
|
|
|
|
0
|
last if( defined( $id ) ); |
380
|
|
|
|
|
|
|
} |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
64
|
50
|
|
|
|
191
|
if( !defined( $id ) ) |
384
|
|
|
|
|
|
|
{ |
385
|
|
|
|
|
|
|
## $self->message( 3, "Could not open shared memory with flags '$flags': $!" ); |
386
|
0
|
|
|
|
|
0
|
return( $self->error( "Unable to create shared memory id with key \"$serial\" and flags \"$flags\": $!" ) ); |
387
|
|
|
|
|
|
|
} |
388
|
64
|
|
|
|
|
220
|
$self->serial( $serial ); |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
## $self->message( 3, "Shared memory created with id \"$id\"." ); |
391
|
|
|
|
|
|
|
## The value 3 can be anything above 0 and below the limit set by SEMMSL. On Linux system, this is usually 32,000. Seem semget(2) man page |
392
|
64
|
|
|
|
|
1660
|
my $semid = semget( $serial, 3, $flags ); |
393
|
64
|
50
|
|
|
|
255
|
if( !defined( $semid ) ) |
394
|
|
|
|
|
|
|
{ |
395
|
|
|
|
|
|
|
## $self->message( 3, "Could not get a semaphore, trying again with creating it." ); |
396
|
0
|
|
|
|
|
0
|
my $newflags = ( $flags | IPC_CREAT ); |
397
|
0
|
|
|
|
|
0
|
$semid = semget( $serial, 3, $newflags ); |
398
|
0
|
0
|
0
|
|
|
0
|
return( $self->error( "Unable to get a semaphore for shared memory key \"", ( $opts->{key} || $self->key ), "\" wth id \"$id\": $!" ) ) if( !defined( $semid ) ); |
399
|
|
|
|
|
|
|
## $self->message( 3, "Retrieved existing semaphore with semaphore id \"$semid\"." ); |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
## $self->message( 3, "Semaphore id is '$semid'" ); |
402
|
|
|
|
|
|
|
my $new = $self->new( |
403
|
64
|
|
50
|
|
|
412
|
key => $opts->{key} || $self->key, |
404
|
|
|
|
|
|
|
debug => $self->debug, |
405
|
|
|
|
|
|
|
mode => $self->mode, |
406
|
|
|
|
|
|
|
) || return; |
407
|
64
|
|
|
|
|
250
|
$new->id( $id ); |
408
|
64
|
|
|
|
|
413
|
$new->semid( $semid ); |
409
|
64
|
50
|
|
|
|
1191
|
if( !defined( $new->op( @{$SEMOP_ARGS->{LOCK_SH}} ) ) ) |
|
64
|
|
|
|
|
341
|
|
410
|
|
|
|
|
|
|
{ |
411
|
0
|
|
|
|
|
0
|
return( $self->error( "Unable to set lock on sempahore: $!" ) ); |
412
|
|
|
|
|
|
|
} |
413
|
|
|
|
|
|
|
|
414
|
64
|
|
|
|
|
414
|
my $there = $new->stat( SEM_MARKER ); |
415
|
64
|
|
|
|
|
328
|
$new->size( $opts->{size} ); |
416
|
64
|
|
|
|
|
1265
|
$new->flags( $flags ); |
417
|
64
|
100
|
|
|
|
217
|
if( $there == SHM_EXISTS ) |
418
|
|
|
|
|
|
|
{ |
419
|
|
|
|
|
|
|
## $self->message( 3, "Binding to existing segment on ", $new->id ); |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
else |
422
|
|
|
|
|
|
|
{ |
423
|
|
|
|
|
|
|
## $self->message( 3, "New segment on ", $new->id ); |
424
|
|
|
|
|
|
|
## We initialise the semaphore with value of 1 |
425
|
51
|
50
|
|
|
|
185
|
$new->stat( SEM_MARKER, SHM_EXISTS ) || |
426
|
|
|
|
|
|
|
return( $self->error( "Unable to set semaphore during object creation: $!" ) ); |
427
|
|
|
|
|
|
|
## $self->message( 3, "Semaphore created." ); |
428
|
51
|
|
|
|
|
1497
|
$SHEM_REPO->{ $id } = $new; |
429
|
|
|
|
|
|
|
} |
430
|
64
|
|
|
|
|
137
|
$new->op( @{$SEMOP_ARGS->{(LOCK_SH | LOCK_UN)}} ); |
|
64
|
|
|
|
|
350
|
|
431
|
|
|
|
|
|
|
## $self->message( 3, "Returning new object persuant to open" ); |
432
|
64
|
|
|
|
|
458
|
return( $new ); |
433
|
|
|
|
|
|
|
} |
434
|
|
|
|
|
|
|
|
435
|
11
|
|
|
11
|
1
|
684
|
sub owner { return( shift->_set_get_scalar( 'owner', @_ ) ); } |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
sub pid |
438
|
|
|
|
|
|
|
{ |
439
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
440
|
0
|
|
|
|
|
0
|
my $sem = shift( @_ ); |
441
|
0
|
0
|
0
|
|
|
0
|
my $semid = $self->semid || |
442
|
|
|
|
|
|
|
return( $self->error( "No semaphore set yet. You must open the shared memory first to remove semaphore." ) ) if( !length( $id ) ); |
443
|
0
|
|
|
|
|
0
|
my $v = semctl( $semid, $sem, GETPID, 0 ); |
444
|
0
|
0
|
|
|
|
0
|
return( $v ? 0 + $v : undef() ); |
445
|
|
|
|
|
|
|
} |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
sub rand |
448
|
|
|
|
|
|
|
{ |
449
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
450
|
0
|
|
0
|
|
|
0
|
my $size = $self->size || 1024; |
451
|
0
|
|
0
|
|
|
0
|
my $key = shmget( IPC_PRIVATE, $size, S_IRWXU|S_IRWXG|S_IRWXO ) || |
452
|
|
|
|
|
|
|
return( $self->error( "Unable to generate a share memory key: $!" ) ); |
453
|
0
|
|
|
|
|
0
|
return( $key ); |
454
|
|
|
|
|
|
|
} |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
## $self->read( $buffer, $size ); |
457
|
|
|
|
|
|
|
sub read |
458
|
|
|
|
|
|
|
{ |
459
|
13
|
|
|
13
|
1
|
3295259
|
my $self = shift( @_ ); |
460
|
13
|
|
|
|
|
63
|
my $id = $self->id; |
461
|
|
|
|
|
|
|
## Optional length parameter for non-reference data only |
462
|
13
|
|
50
|
|
|
100
|
my $size = int( $_[1] || $self->size || SHM_BUFSIZ ); |
463
|
|
|
|
|
|
|
## $self->message( 3, "Reading $size bytes of data from memory for id '$id'." ); |
464
|
13
|
50
|
|
|
|
319
|
return( $self->error( "No shared memory id! Have you opened it first?" ) ) if( !length( $id ) ); |
465
|
13
|
|
|
|
|
28
|
my $buffer = ''; |
466
|
13
|
|
|
|
|
52
|
my $addr = $self->addr; |
467
|
13
|
50
|
|
|
|
198
|
if( $addr ) |
468
|
|
|
|
|
|
|
{ |
469
|
0
|
0
|
|
|
|
0
|
memread( $addr, $buffer, 0, $size ) || |
470
|
|
|
|
|
|
|
return( $self->error( "Unable to read data from shared memory address \"$addr\" using memread: $!" ) ); |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
else |
473
|
|
|
|
|
|
|
{ |
474
|
13
|
50
|
|
|
|
6231
|
shmread( $id, $buffer, 0, $size ) || |
475
|
|
|
|
|
|
|
return( $self->error( "Unable to read data from shared memory id \"$id\": $!" ) ); |
476
|
|
|
|
|
|
|
} |
477
|
|
|
|
|
|
|
## Get rid of nulls end padded |
478
|
13
|
|
|
|
|
5150
|
$buffer = unpack( "A*", $buffer ); |
479
|
|
|
|
|
|
|
## $self->message( 3, "Data retrieved is '$buffer'." ); |
480
|
13
|
|
|
|
|
60
|
my $first_char = substr( $buffer, 0, 1 ); |
481
|
13
|
|
|
|
|
198
|
my $j = JSON->new->utf8->relaxed->allow_nonref; |
482
|
13
|
|
|
|
|
33
|
my $data; |
483
|
13
|
|
|
|
|
17
|
try |
484
|
13
|
|
|
13
|
|
20
|
{ |
485
|
|
|
|
|
|
|
## Does the value have any typical json format? " for a string, { for an hash and [ for an array |
486
|
13
|
100
|
66
|
|
|
147
|
if( $first_char eq '"' || $first_char eq '{' || $first_char eq '[' ) |
|
|
|
66
|
|
|
|
|
487
|
|
|
|
|
|
|
{ |
488
|
11
|
|
|
|
|
149
|
$data = $j->decode( $buffer ); |
489
|
|
|
|
|
|
|
} |
490
|
|
|
|
|
|
|
else |
491
|
|
|
|
|
|
|
{ |
492
|
2
|
|
|
|
|
8
|
$data = $buffer; |
493
|
|
|
|
|
|
|
} |
494
|
|
|
|
|
|
|
} |
495
|
13
|
50
|
|
|
|
182
|
catch( $e ) |
|
13
|
100
|
|
|
|
49
|
|
|
13
|
50
|
|
|
|
49
|
|
|
13
|
0
|
|
|
|
23
|
|
|
13
|
50
|
|
|
|
36
|
|
|
13
|
|
|
|
|
18
|
|
|
13
|
|
|
|
|
20
|
|
|
13
|
|
|
|
|
26
|
|
|
13
|
|
|
|
|
54
|
|
|
0
|
|
|
|
|
0
|
|
|
12
|
|
|
|
|
29
|
|
|
1
|
|
|
|
|
23
|
|
|
13
|
|
|
|
|
66
|
|
|
13
|
|
|
|
|
33
|
|
|
13
|
|
|
|
|
48
|
|
|
13
|
|
|
|
|
37
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
496
|
0
|
|
|
0
|
|
0
|
{ |
497
|
0
|
0
|
|
|
|
0
|
$self->error( "An error occured while json decoding data: $e", ( length( $buffer ) <= 1024 ? "\nData is: '$buffer'" : '' ) ); |
498
|
|
|
|
|
|
|
## Maybe it's a string that starts with '{' or " or [ and triggered an error because it was not actually json data? |
499
|
|
|
|
|
|
|
## So we return the data stored as it is |
500
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
501
|
|
|
|
|
|
|
{ |
502
|
0
|
|
|
|
|
0
|
$_[0] = $buffer; |
503
|
0
|
|
0
|
|
|
0
|
return( length( $buffer ) || "0E0" ); |
504
|
|
|
|
|
|
|
} |
505
|
|
|
|
|
|
|
else |
506
|
|
|
|
|
|
|
{ |
507
|
0
|
|
|
|
|
0
|
return( $buffer ); |
508
|
|
|
|
|
|
|
} |
509
|
0
|
0
|
33
|
|
|
0
|
} |
|
0
|
0
|
66
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
13
|
|
|
|
|
287
|
|
|
0
|
|
|
|
|
0
|
|
510
|
|
|
|
|
|
|
|
511
|
13
|
100
|
|
|
|
50
|
if( @_ ) |
512
|
|
|
|
|
|
|
{ |
513
|
11
|
|
|
|
|
34
|
my $len = length( $_[0] ); |
514
|
|
|
|
|
|
|
## If the decoded data is not a reference of any sort, and the length parameter was provided |
515
|
11
|
100
|
|
|
|
51
|
if( !ref( $data ) ) |
516
|
|
|
|
|
|
|
{ |
517
|
2
|
50
|
|
|
|
18
|
$_[0] = $size > 0 ? substr( $data, 0, $size ) : $data; |
518
|
2
|
|
50
|
|
|
38
|
return( length( $_[0] ) || "0E0" ); |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
else |
521
|
|
|
|
|
|
|
{ |
522
|
9
|
|
|
|
|
32
|
$_[0] = $data; |
523
|
9
|
|
50
|
|
|
116
|
return( $len || "0E0" ); |
524
|
|
|
|
|
|
|
} |
525
|
|
|
|
|
|
|
} |
526
|
|
|
|
|
|
|
else |
527
|
|
|
|
|
|
|
{ |
528
|
2
|
|
|
|
|
17
|
return( $data ); |
529
|
|
|
|
|
|
|
} |
530
|
|
|
|
|
|
|
} |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
sub remove |
533
|
|
|
|
|
|
|
{ |
534
|
2
|
|
|
2
|
1
|
13
|
my $self = shift( @_ ); |
535
|
2
|
50
|
|
|
|
15
|
return( 1 ) if( $self->removed ); |
536
|
2
|
|
|
|
|
189
|
my $id = $self->id(); |
537
|
|
|
|
|
|
|
## $self->message( 3, "Called to remove shared memory id \"$id\"." ); |
538
|
2
|
50
|
|
|
|
18
|
return( $self->error( "No shared memory id! Have you opened it first?" ) ) if( !length( $id ) ); |
539
|
2
|
|
|
|
|
9
|
my $semid = $self->semid; |
540
|
2
|
50
|
|
|
|
48
|
return( $self->error( "No semaphore set yet. You must open the shared memory first to remove semaphore." ) ) if( !length( $semid ) ); |
541
|
2
|
|
|
|
|
14
|
$self->unlock(); |
542
|
|
|
|
|
|
|
## Remove share memory segment |
543
|
2
|
50
|
|
|
|
61
|
if( !defined( shmctl( $id, IPC_RMID, 0 ) ) ) |
544
|
|
|
|
|
|
|
{ |
545
|
0
|
|
|
|
|
0
|
return( $self->error( "Unable to remove share memory segement id '$id' (IPC_RMID is '", IPC_RMID, "'): $!" ) ); |
546
|
|
|
|
|
|
|
} |
547
|
|
|
|
|
|
|
## Remove semaphore |
548
|
2
|
|
|
|
|
239
|
my $rv; |
549
|
2
|
50
|
|
|
|
9
|
if( !defined( $rv = semctl( $semid, 0, IPC_RMID, 0 ) ) ) |
550
|
|
|
|
|
|
|
{ |
551
|
0
|
|
|
|
|
0
|
$self->error( "Warning only: could not remove the semaphore id \"$semid\": $!" ); |
552
|
|
|
|
|
|
|
} |
553
|
2
|
50
|
|
|
|
43
|
$self->removed( $rv ? 1 : 0 ); |
554
|
2
|
50
|
|
|
|
125
|
if( $rv ) |
555
|
|
|
|
|
|
|
{ |
556
|
2
|
|
|
|
|
18
|
delete( $SHEM_REPO->{ $id } ); |
557
|
2
|
|
|
|
|
19
|
$self->id( undef() ); |
558
|
2
|
|
|
|
|
12
|
$self->semid( undef() ); |
559
|
|
|
|
|
|
|
} |
560
|
2
|
50
|
|
|
|
59
|
return( $rv ? 1 : 0 ); |
561
|
|
|
|
|
|
|
} |
562
|
|
|
|
|
|
|
|
563
|
4
|
|
|
4
|
1
|
41
|
sub removed { return( shift->_set_get_boolean( 'removed', @_ ) ); } |
564
|
|
|
|
|
|
|
|
565
|
336
|
|
|
336
|
1
|
1046
|
sub semid { return( shift->_set_get_scalar( 'semid', @_ ) ); } |
566
|
|
|
|
|
|
|
|
567
|
130
|
|
|
130
|
1
|
532
|
sub serial { return( shift->_set_get_scalar( 'serial', @_ ) ); } |
568
|
|
|
|
|
|
|
|
569
|
214
|
|
|
214
|
1
|
1664
|
sub size { return( shift->_set_get_scalar( 'size', @_ ) ); } |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
sub stat |
572
|
|
|
|
|
|
|
{ |
573
|
115
|
|
|
115
|
1
|
218
|
my $self = shift( @_ ); |
574
|
115
|
|
|
|
|
234
|
my $id = $self->semid; |
575
|
115
|
50
|
|
|
|
1645
|
return( $self->error( "No semaphore set yet. You must open the shared memory first to set the semaphore." ) ) if( !length( $id ) ); |
576
|
115
|
50
|
|
|
|
262
|
if( @_ ) |
577
|
|
|
|
|
|
|
{ |
578
|
115
|
100
|
|
|
|
277
|
if( @_ == 1 ) |
579
|
|
|
|
|
|
|
{ |
580
|
64
|
|
|
|
|
135
|
my $sem = shift( @_ ); |
581
|
|
|
|
|
|
|
## $self->message( 3, "Retrieving semaphore value for '$sem'" ); |
582
|
64
|
|
|
|
|
279
|
my $v = semctl( $id, $sem, GETVAL, 0 ); |
583
|
64
|
50
|
|
|
|
1484
|
return( $v ? 0 + $v : undef() ); |
584
|
|
|
|
|
|
|
} |
585
|
|
|
|
|
|
|
else |
586
|
|
|
|
|
|
|
{ |
587
|
51
|
|
|
|
|
136
|
my( $sem, $val ) = @_; |
588
|
|
|
|
|
|
|
## $self->message( 3, "Setting semaphore '$sem' with value '$val'." ); |
589
|
51
|
|
|
|
|
253
|
return( semctl( $id, $sem, SETVAL, $val ) ); |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
} |
592
|
|
|
|
|
|
|
else |
593
|
|
|
|
|
|
|
{ |
594
|
0
|
|
|
|
|
0
|
my $data = ''; |
595
|
0
|
0
|
|
|
|
0
|
if( wantarray() ) |
596
|
|
|
|
|
|
|
{ |
597
|
|
|
|
|
|
|
## $self->message( 3, "Returning all semaphore data." ); |
598
|
0
|
0
|
|
|
|
0
|
semctl( $id, 0, GETALL, $data ) || return( () ); |
599
|
0
|
|
|
|
|
0
|
return( ( unpack( "s*", $data ) ) ); |
600
|
|
|
|
|
|
|
} |
601
|
|
|
|
|
|
|
else |
602
|
|
|
|
|
|
|
{ |
603
|
|
|
|
|
|
|
## $self->message( 3, "Returning all semaphore data as Apache2::SSI::SemStat object." ); |
604
|
0
|
0
|
|
|
|
0
|
semctl( $id, 0, IPC_STAT, $data ) || |
605
|
|
|
|
|
|
|
return( $self->error( "Unable to stat semaphore with id '$id': $!" ) ); |
606
|
0
|
|
|
|
|
0
|
return( Apache2::SSI::SemStat->new->unpack( $data ) ); |
607
|
|
|
|
|
|
|
} |
608
|
|
|
|
|
|
|
} |
609
|
|
|
|
|
|
|
} |
610
|
|
|
|
|
|
|
|
611
|
128
|
|
|
128
|
1
|
2044
|
sub supported { return( $SYSV_SUPPORTED ); } |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
sub unlock |
614
|
|
|
|
|
|
|
{ |
615
|
18
|
|
|
18
|
1
|
64
|
my $self = shift( @_ ); |
616
|
18
|
100
|
|
|
|
92
|
return( 1 ) if( !$self->locked ); |
617
|
6
|
|
|
|
|
131
|
my $semid = $self->semid; |
618
|
6
|
50
|
|
|
|
111
|
return( $self->error( "No semaphore set yet. You must open the shared memory first to unlock semaphore." ) ) if( !length( $semid ) ); |
619
|
|
|
|
|
|
|
## $self->message( 3, "Removing lock for semaphore id \"$semid\" and locked value '$self->{locked}'." ); |
620
|
6
|
|
|
|
|
35
|
my $type = $self->locked | LOCK_UN; |
621
|
6
|
100
|
|
|
|
103
|
$type ^= LOCK_NB if( $type & LOCK_NB ); |
622
|
6
|
50
|
|
|
|
21
|
if( defined( $self->op( @{$SEMOP_ARGS->{ $type }} ) ) ) |
|
6
|
|
|
|
|
35
|
|
623
|
|
|
|
|
|
|
{ |
624
|
6
|
|
|
|
|
28
|
$self->locked( 0 ); |
625
|
|
|
|
|
|
|
} |
626
|
6
|
|
|
|
|
133
|
return( $self ); |
627
|
|
|
|
|
|
|
} |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
sub write |
630
|
|
|
|
|
|
|
{ |
631
|
7
|
|
|
7
|
1
|
673
|
my $self = shift( @_ ); |
632
|
7
|
50
|
|
|
|
66
|
my $data = ( @_ == 1 ) ? shift( @_ ) : join( '', @_ ); |
633
|
7
|
|
|
|
|
30
|
my $id = $self->id(); |
634
|
7
|
|
50
|
|
|
23
|
my $size = int( $self->size() ) || SHM_BUFSIZ; |
635
|
7
|
|
|
|
|
143
|
my @callinfo = caller; |
636
|
|
|
|
|
|
|
## $self->message( 3, "Called from file $callinfo[1] at line $callinfo[2]" ); |
637
|
|
|
|
|
|
|
## $self->message( 3, "Size limit set to '$size'" ); |
638
|
7
|
|
|
|
|
96
|
my $j = JSON->new->utf8->relaxed->allow_nonref->convert_blessed; |
639
|
7
|
|
|
|
|
13
|
my $encoded; |
640
|
7
|
|
|
|
|
12
|
try |
641
|
7
|
|
|
7
|
|
12
|
{ |
642
|
7
|
|
|
|
|
73
|
$encoded = $j->encode( $data ); |
643
|
|
|
|
|
|
|
} |
644
|
7
|
50
|
|
|
|
51
|
catch( $e ) |
|
7
|
50
|
|
|
|
28
|
|
|
7
|
50
|
|
|
|
21
|
|
|
7
|
0
|
|
|
|
14
|
|
|
7
|
50
|
|
|
|
21
|
|
|
7
|
|
|
|
|
8
|
|
|
7
|
|
|
|
|
12
|
|
|
7
|
|
|
|
|
20
|
|
|
7
|
|
|
|
|
25
|
|
|
0
|
|
|
|
|
0
|
|
|
7
|
|
|
|
|
20
|
|
|
0
|
|
|
|
|
0
|
|
|
7
|
|
|
|
|
32
|
|
|
7
|
|
|
|
|
15
|
|
|
7
|
|
|
|
|
16
|
|
|
7
|
|
|
|
|
27
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
645
|
0
|
|
|
0
|
|
0
|
{ |
646
|
0
|
|
|
|
|
0
|
return( $self->error( "An error occured json encoding data provided: $e" ) ); |
647
|
0
|
0
|
33
|
|
|
0
|
} |
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
7
|
|
|
|
|
145
|
|
|
0
|
|
|
|
|
0
|
|
648
|
|
|
|
|
|
|
|
649
|
7
|
50
|
|
|
|
32
|
if( length( $encoded ) > $size ) |
650
|
|
|
|
|
|
|
{ |
651
|
0
|
|
|
|
|
0
|
return( $self->error( "Data to write are ", length( $encoded ), " bytes long and exceed the maximum you have set of '$size'." ) ); |
652
|
|
|
|
|
|
|
} |
653
|
|
|
|
|
|
|
## $self->message( 3, "Storing ", length( $encoded ), " bytes of data", ( length( $encoded ) <= 2048 ? ":\n'$encoded'" : '.' ) ); |
654
|
|
|
|
|
|
|
## $size = length( $encoded ); |
655
|
7
|
|
|
|
|
24
|
my $addr = $self->addr; |
656
|
7
|
50
|
|
|
|
118
|
if( $addr ) |
657
|
|
|
|
|
|
|
{ |
658
|
0
|
0
|
|
|
|
0
|
memwrite( $addr, $encoded, 0, $size ) || |
659
|
|
|
|
|
|
|
return( $self->error( "Unable to write to shared memory address '$addr' using memwrite: $!" ) ); |
660
|
|
|
|
|
|
|
} |
661
|
|
|
|
|
|
|
else |
662
|
|
|
|
|
|
|
{ |
663
|
7
|
50
|
|
|
|
2677
|
shmwrite( $id, $encoded, 0, $size ) || |
664
|
|
|
|
|
|
|
return( $self->error( "Unable to write to shared memory id '$id': $!" ) ); |
665
|
|
|
|
|
|
|
} |
666
|
|
|
|
|
|
|
## $self->message( 3, "Successfully wrote ", length( $encoded ), " bytes of data to memory." ); |
667
|
7
|
|
|
|
|
126
|
return( $self ); |
668
|
|
|
|
|
|
|
} |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
sub _str2key |
671
|
|
|
|
|
|
|
{ |
672
|
128
|
|
|
128
|
|
237
|
my $self = shift( @_ ); |
673
|
128
|
|
|
|
|
259
|
my $key = shift( @_ ); |
674
|
128
|
50
|
33
|
|
|
1230
|
if( !defined( $key ) || $key eq '' ) |
|
|
50
|
|
|
|
|
|
675
|
|
|
|
|
|
|
{ |
676
|
0
|
|
|
|
|
0
|
return( IPC_PRIVATE ); |
677
|
|
|
|
|
|
|
} |
678
|
|
|
|
|
|
|
elsif( $key =~ /^\d+$/ ) |
679
|
|
|
|
|
|
|
{ |
680
|
0
|
|
|
|
|
0
|
return( IPC::SysV::ftok( __FILE__, $key ) ); |
681
|
|
|
|
|
|
|
} |
682
|
|
|
|
|
|
|
else |
683
|
|
|
|
|
|
|
{ |
684
|
128
|
|
|
|
|
253
|
my $id = 0; |
685
|
128
|
|
|
|
|
894
|
$id += $_ for( unpack( "C*", $key ) ); |
686
|
|
|
|
|
|
|
## We use the root as a reliable and stable path. |
687
|
|
|
|
|
|
|
## I initially though about using __FILE__, but during testing this would be in ./blib/lib and beside one user might use a version of this module somewhere while the one used under Apache/mod_perl2 could be somewhere else and this would render the generation of the IPC key unreliable and unrepeatable |
688
|
128
|
|
|
|
|
2174
|
my $val = IPC::SysV::ftok( '/', $id ); |
689
|
|
|
|
|
|
|
## $self->message( 3, "Calling IPC::SysV::ftok for key '$key' with file '/' and numeric id '$id' returning '$val'." ); |
690
|
128
|
|
|
|
|
613
|
return( $val ); |
691
|
|
|
|
|
|
|
} |
692
|
|
|
|
|
|
|
} |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
END |
695
|
|
|
|
|
|
|
{ |
696
|
15
|
|
|
15
|
|
37085
|
foreach my $id ( keys( %$SHEM_REPO ) ) |
697
|
|
|
|
|
|
|
{ |
698
|
10
|
|
|
|
|
36
|
my $s = $SHEM_REPO->{ $id }; |
699
|
10
|
|
|
|
|
94
|
$s->message( 3, "Cleaning up for shared memory id '$id' with destroy value '", $s->destroy, "' and owner '", $s->owner, "' vs pid '$$'." ); |
700
|
10
|
|
|
|
|
489
|
$s->unlock; |
701
|
10
|
50
|
|
|
|
198
|
next unless( $s->destroy ); |
702
|
0
|
0
|
|
|
|
0
|
next unless( $s->owner == $$ ); |
703
|
0
|
|
|
|
|
0
|
$s->remove; |
704
|
|
|
|
|
|
|
} |
705
|
|
|
|
|
|
|
}; |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
# DESTROY |
708
|
|
|
|
|
|
|
# { |
709
|
|
|
|
|
|
|
# my $self = shift( @_ ); |
710
|
|
|
|
|
|
|
# my @callinfo = caller; |
711
|
|
|
|
|
|
|
# ## $self->message( 3, "Got here from package $callinfo[0] in file $callinfo[1] at line $callinfo[2], destroying object for shared memory id \"", $self->id, "\" key \"", $self->key, "\" with destroy flags '", $self->destroy, "'." ); |
712
|
|
|
|
|
|
|
# ## $self->message( 3, "Object contains following keys: ", sub{ $self->dump( $self ) } ); |
713
|
|
|
|
|
|
|
# $self->unlock; |
714
|
|
|
|
|
|
|
# $self->remove if( $self->destroy ); |
715
|
|
|
|
|
|
|
# }; |
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
{ |
719
|
|
|
|
|
|
|
package |
720
|
|
|
|
|
|
|
Apache2::SSI::SemStat; |
721
|
|
|
|
|
|
|
our $VERSION = 'v0.1.0'; |
722
|
|
|
|
|
|
|
|
723
|
15
|
|
|
15
|
|
194
|
use constant UID => 0; |
|
15
|
|
|
|
|
38
|
|
|
15
|
|
|
|
|
1208
|
|
724
|
15
|
|
|
15
|
|
112
|
use constant GID => 1; |
|
15
|
|
|
|
|
31
|
|
|
15
|
|
|
|
|
659
|
|
725
|
15
|
|
|
15
|
|
89
|
use constant CUID => 2; |
|
15
|
|
|
|
|
33
|
|
|
15
|
|
|
|
|
607
|
|
726
|
15
|
|
|
15
|
|
80
|
use constant CGID => 3; |
|
15
|
|
|
|
|
31
|
|
|
15
|
|
|
|
|
934
|
|
727
|
15
|
|
|
15
|
|
81
|
use constant MODE => 4; |
|
15
|
|
|
|
|
29
|
|
|
15
|
|
|
|
|
598
|
|
728
|
15
|
|
|
15
|
|
83
|
use constant CTIME => 5; |
|
15
|
|
|
|
|
30
|
|
|
15
|
|
|
|
|
591
|
|
729
|
15
|
|
|
15
|
|
78
|
use constant OTIME => 6; |
|
15
|
|
|
|
|
31
|
|
|
15
|
|
|
|
|
557
|
|
730
|
15
|
|
|
15
|
|
77
|
use constant NSEMS => 7; |
|
15
|
|
|
|
|
29
|
|
|
15
|
|
|
|
|
2956
|
|
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
sub new |
733
|
|
|
|
|
|
|
{ |
734
|
0
|
|
|
0
|
|
|
my $this = shift( @_ ); |
735
|
0
|
|
|
|
|
|
my @vals = @_; |
736
|
0
|
|
0
|
|
|
|
return( bless( [ @vals ] => ref( $this ) || $this ) ); |
737
|
|
|
|
|
|
|
} |
738
|
|
|
|
|
|
|
|
739
|
0
|
|
|
0
|
|
|
sub cgid { return( shift->[CGID] ); } |
740
|
|
|
|
|
|
|
|
741
|
0
|
|
|
0
|
|
|
sub ctime { return( shift->[CTIME] ); } |
742
|
|
|
|
|
|
|
|
743
|
0
|
|
|
0
|
|
|
sub cuid { return( shift->[CUID] ); } |
744
|
|
|
|
|
|
|
|
745
|
0
|
|
|
0
|
|
|
sub gid { return( shift->[GID] ); } |
746
|
|
|
|
|
|
|
|
747
|
0
|
|
|
0
|
|
|
sub mode { return( shift->[MODE] ); } |
748
|
|
|
|
|
|
|
|
749
|
0
|
|
|
0
|
|
|
sub nsems { return( shift->[NSEMS] ); } |
750
|
|
|
|
|
|
|
|
751
|
0
|
|
|
0
|
|
|
sub otime { return( shift->[OTIME] ); } |
752
|
|
|
|
|
|
|
|
753
|
0
|
|
|
0
|
|
|
sub uid { return( shift->[UID] ); } |
754
|
|
|
|
|
|
|
} |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
1; |
757
|
|
|
|
|
|
|
|