1################################################################################ 2# 3# Version 2.x, Copyright (C) 2007-2013, Marcus Holland-Moritz <mhx@cpan.org>. 4# Version 1.x, Copyright (C) 1999, Graham Barr <gbarr@pobox.com>. 5# 6# This program is free software; you can redistribute it and/or 7# modify it under the same terms as Perl itself. 8# 9################################################################################ 10 11use strict; 12use warnings; 13 14our %Config; 15BEGIN { 16 require Test::More; Test::More->import; 17 require Config; Config->import; 18 19 if ($ENV{'PERL_CORE'} && $Config{'extensions'} !~ m[\bIPC/SysV\b]) { 20 plan(skip_all => 'IPC::SysV was not built'); 21 } 22} 23 24if ($Config{'d_sem'} ne 'define') { 25 plan(skip_all => '$Config{d_sem} undefined'); 26} 27elsif ($Config{'d_msg'} ne 'define') { 28 plan(skip_all => '$Config{d_msg} undefined'); 29} 30 31plan(tests => 39); 32 33# These constants are common to all tests. 34# Later the sem* tests will import more for themselves. 35 36use IPC::SysV qw(IPC_PRIVATE IPC_NOWAIT IPC_STAT IPC_RMID S_IRWXU); 37 38{ 39 my $did_diag = 0; 40 41 sub do_sys_diag 42 { 43 return if $did_diag++; 44 45 if ($^O eq 'cygwin') { 46 diag(<<EOM); 47 48It may be that the cygserver service isn't running. 49 50EOM 51 52 diag(<<EOM) unless exists $ENV{CYGWIN} && $ENV{CYGWIN} eq 'server'; 53You also may have to set the CYGWIN environment variable 54to 'server' before running the test suite: 55 56 export CYGWIN=server 57 58EOM 59 } 60 else { 61 diag(<<EOM); 62 63It may be that your kernel does not have SysV IPC configured. 64 65EOM 66 67 diag(<<EOM) if $^O eq 'freebsd'; 68You must have following options in your kernel: 69 70options SYSVSHM 71options SYSVSEM 72options SYSVMSG 73 74See config(8). 75 76EOM 77 } 78 } 79} 80 81{ 82 my $SIGSYS_caught = 0; 83 84 sub skip_or_die 85 { 86 my($what, $why) = @_; 87 if ($SIGSYS_caught) { 88 do_sys_diag(); 89 return "$what failed: SIGSYS caught"; 90 } 91 my $info = "$what failed: $why"; 92 if ($why == &IPC::SysV::ENOSPC || $why == &IPC::SysV::ENOSYS || 93 $why == &IPC::SysV::ENOMEM || $why == &IPC::SysV::EACCES) { 94 do_sys_diag() if $why == &IPC::SysV::ENOSYS; 95 return $info; 96 } 97 die $info; 98 } 99 100 sub catchsig 101 { 102 my $code = shift; 103 if (exists $SIG{SYS}) { 104 local $SIG{SYS} = sub { $SIGSYS_caught++ }; 105 return $code->(); 106 } 107 return $code->(); 108 } 109} 110 111# FreeBSD and cygwin are known to throw this if there's no SysV IPC 112# in the kernel or the cygserver isn't running properly. 113if (exists $SIG{SYS}) { # No SIGSYS with older perls... 114 $SIG{SYS} = sub { 115 do_sys_diag(); 116 diag('Bail out! SIGSYS caught'); 117 exit(1); 118 }; 119} 120 121my $msg; 122 123my $perm = S_IRWXU; 124my $test_name; 125my $N = do { my $foo = eval { pack "L!", 0 }; $@ ? '' : '!' }; 126 127SKIP: { 128 skip('lacking d_msgget d_msgctl d_msgsnd d_msgrcv', 6) unless 129 $Config{'d_msgget'} eq 'define' && 130 $Config{'d_msgctl'} eq 'define' && 131 $Config{'d_msgsnd'} eq 'define' && 132 $Config{'d_msgrcv'} eq 'define'; 133 134 $msg = catchsig(sub { msgget(IPC_PRIVATE, $perm) }); 135 136 # Very first time called after machine is booted value may be 0 137 unless (defined $msg && $msg >= 0) { 138 skip(skip_or_die('msgget', $!), 6); 139 } 140 141 pass('msgget IPC_PRIVATE S_IRWXU'); 142 143 #Putting a message on the queue 144 my $msgtype = 1; 145 my $msgtext = "hello"; 146 147 my $test2bad; 148 my $test5bad; 149 my $test6bad; 150 151 $test_name = 'queue a message'; 152 153 if (msgsnd($msg, pack("L$N a*", $msgtype, $msgtext), IPC_NOWAIT)) { 154 pass($test_name); 155 } 156 else { 157 fail($test_name); 158 $test2bad = 1; 159 diag(<<EOM); 160The failure of the subtest #2 may indicate that the message queue 161resource limits either of the system or of the testing account 162have been reached. Error message "Operating would block" is 163usually indicative of this situation. The error message was now: 164"$!" 165 166You can check the message queues with the 'ipcs' command and 167you can remove unneeded queues with the 'ipcrm -q id' command. 168You may also consider configuring your system or account 169to have more message queue resources. 170 171Because of the subtest #2 failing also the substests #5 and #6 will 172very probably also fail. 173EOM 174 } 175 176 my $data = ''; 177 ok(msgctl($msg, IPC_STAT, $data), 'msgctl IPC_STAT call'); 178 179 cmp_ok(length($data), '>', 0, 'msgctl IPC_STAT data'); 180 181 $test_name = 'message get call'; 182 183 my $msgbuf = ''; 184 if (msgrcv($msg, $msgbuf, 256, 0, IPC_NOWAIT)) { 185 pass($test_name); 186 } 187 else { 188 fail($test_name); 189 $test5bad = 1; 190 } 191 if ($test5bad && $test2bad) { 192 diag(<<EOM); 193This failure was to be expected because the subtest #2 failed. 194EOM 195 } 196 197 $test_name = 'message get data'; 198 199 my($rmsgtype, $rmsgtext); 200 ($rmsgtype, $rmsgtext) = unpack("L$N a*", $msgbuf); 201 202 if ($rmsgtype == $msgtype && $rmsgtext eq $msgtext) { 203 pass($test_name); 204 } 205 else { 206 fail($test_name); 207 $test6bad = 1; 208 } 209 210 if ($test6bad && $test2bad) { 211 print <<EOM; 212This failure was to be expected because the subtest #2 failed. 213EOM 214 } 215} 216 217my $sem; 218 219SKIP: { 220 skip('lacking d_semget d_semctl', 11) unless 221 $Config{'d_semget'} eq 'define' && 222 $Config{'d_semctl'} eq 'define'; 223 224 use IPC::SysV qw(IPC_CREAT GETALL SETALL); 225 226 # FreeBSD's default limit seems to be 9 227 my $nsem = 5; 228 229 $sem = catchsig(sub { semget(IPC_PRIVATE, $nsem, $perm | IPC_CREAT) }); 230 231 # Very first time called after machine is booted value may be 0 232 unless (defined $sem && $sem >= 0) { 233 skip(skip_or_die('semget', $!), 11); 234 } 235 236 pass('sem acquire'); 237 238 my $data = ''; 239 ok(semctl($sem, 0, IPC_STAT, $data), 'sem data call'); 240 241 cmp_ok(length($data), '>', 0, 'sem data len'); 242 243 ok(semctl($sem, 0, SETALL, pack("s$N*", (0) x $nsem)), 'set all sems'); 244 245 $data = ""; 246 ok(semctl($sem, 0, GETALL, $data), 'get all sems'); 247 248 is(length($data), length(pack("s$N*", (0) x $nsem)), 'right length'); 249 250 my @data = unpack("s$N*", $data); 251 252 my $adata = "0" x $nsem; 253 254 is(scalar(@data), $nsem, 'right amount'); 255 cmp_ok(join("", @data), 'eq', $adata, 'right data'); 256 257 my $poke = 2; 258 259 $data[$poke] = 1; 260 ok(semctl($sem, 0, SETALL, pack("s$N*", @data)), 'poke it'); 261 262 $data = ""; 263 ok(semctl($sem, 0, GETALL, $data), 'and get it back'); 264 265 @data = unpack("s$N*", $data); 266 my $bdata = "0" x $poke . "1" . "0" x ($nsem - $poke - 1); 267 268 cmp_ok(join("", @data), 'eq', $bdata, 'changed'); 269} 270 271SKIP: { 272 skip('lacking d_shm', 11) unless 273 $Config{'d_shm'} eq 'define'; 274 275 use IPC::SysV qw(shmat shmdt memread memwrite ftok); 276 277 my $shm = catchsig(sub { shmget(IPC_PRIVATE, 4, S_IRWXU) }); 278 279 # Very first time called after machine is booted value may be 0 280 unless (defined $shm && $shm >= 0) { 281 skip(skip_or_die('shmget', $!), 11); 282 } 283 284 pass("shm acquire"); 285 286 ok(shmwrite($shm, pack("N", 0xdeadbeef), 0, 4), 'shmwrite(0xdeadbeef)'); 287 288 my $addr = shmat($shm, undef, 0); 289 ok(defined $addr, 'shmat'); 290 291 is(unpack("N", unpack("P4", $addr)), 0xdeadbeef, 'read shm by addr'); 292 293 ok(defined shmctl($shm, IPC_RMID, 0), 'shmctl(IPC_RMID)'); 294 295 my $var = ''; 296 ok(memread($addr, $var, 0, 4), 'memread($var)'); 297 298 is(unpack("N", $var), 0xdeadbeef, 'read shm by memread'); 299 300 ok(memwrite($addr, pack("N", 0xbadc0de5), 0, 4), 'memwrite(0xbadc0de5)'); 301 302 is(unpack("N", unpack("P4", $addr)), 0xbadc0de5, 'read modified shm by addr'); 303 304 is(shmat(-1, undef, 0), undef, 'shmat illegal id fails'); 305 306 ok(defined shmdt($addr), 'shmdt'); 307} 308 309SKIP: { 310 skip('lacking d_shm', 11) unless 311 $Config{'d_shm'} eq 'define'; 312 313 use IPC::SysV qw(ftok); 314 315 my $key1i = ftok($0); 316 my $key1e = ftok($0, 1); 317 318 ok(defined $key1i, 'ftok implicit project id'); 319 ok(defined $key1e, 'ftok explicit project id'); 320 is($key1i, $key1e, 'keys match'); 321 322 my $keyAsym = ftok($0, 'A'); 323 my $keyAnum = ftok($0, ord('A')); 324 325 ok(defined $keyAsym, 'ftok symbolic project id'); 326 ok(defined $keyAnum, 'ftok numeric project id'); 327 is($keyAsym, $keyAnum, 'keys match'); 328 329 my $two = '2'; 330 my $key1 = ftok($0, 2); 331 my $key2 = ftok($0, ord('2')); 332 my $key3 = ftok($0, $two); 333 my $key4 = ftok($0, int($two)); 334 335 is($key1, $key4, 'keys match'); 336 isnt($key1, $key2, 'keys do not match'); 337 is($key2, $key3, 'keys match'); 338 339 eval { my $foo = ftok($0, 'AA') }; 340 ok(index($@, 'invalid project id') >= 0, 'ftok error'); 341 342 eval { my $foo = ftok($0, 3.14159) }; 343 ok(index($@, 'invalid project id') >= 0, 'ftok error'); 344} 345 346END { 347 msgctl($msg, IPC_RMID, 0) if defined $msg; 348 semctl($sem, 0, IPC_RMID, 0) if defined $sem; 349} 350