Showing posts with label Perl. Show all posts
Showing posts with label Perl. Show all posts

Sunday, March 13, 2011

Perl pack/unpack notes

Original post

'b' and 'B' formats


The 'b' and 'B' formats pack strings consisting of '0' and '1' characters to bytes and unpack bytes to strings of '0' and '1' characters. Perl treats even valued characters as 0 and odd valued characters as 1 while packing. The difference between the two is the order of the bits within each byte. With 'b', the bits are specified in increasing order. With 'B', in descending order. The count represents the number of bits to pack.

Examples

ord(pack('b8','00100110')) produces 100 (4 + 32 + 64)
ord(pack('B8','00100110')) produces 38 (32 + 4 + 2)

Here "Increasing Order" means from LSB to MSB, "Descending Order" means from MSB to LSB.

'h' and 'H' formats


The 'h' and 'H' formats pack strings containing hexadecimal digits. 'h' takes the low nybble first, 'H' takes the high nybble first. The count represents the number of nybbles to pack. In case you were wondering, a nybble is half a byte.

Examples

Each of the following returns a two byte scalar.
pack('h4','1234') produces 0x21,0x43
pack('H4','1234') produces 0x12,0x34

Wednesday, September 29, 2010

Integer compare with ''

There is a tricky bug if you compare a number with empty string and if the number = 0:
                                                                                                    
#!/usr/bin/perl
#use warnings;
use strict;

my $v;

undef $v;

if (!defined($v)) {
print "Oops! \$v is not defined\n";
}

$v = 0;

if ($v == '') {
print "Oops! \$v == \'\'\n";
}

__END__

Result:
Oops! $v is not defined
Oops! $v == ''


You can see that if $v = 0, the condition:

$v == ''

will get TRUE!

Of course if you turn on warnings, you will not ignore this bug because compiler will give you this:

Argument "" isn't numeric in numeric eq (==) at ...

Thursday, July 8, 2010

Real private method in Perl

For a truly private method, you would usually write the following:


my $_private_method = sub { my ($self, ...) = @_; ... };
...
$self->$_private_method($some, $arguments);
...


which makes the method scoped to the block it was defined in, or the file if it’s not within braces.

This is Perl.

The reason is $_private_method is not special, it's just a "my" variable. So it will be "invisible" outside block or file scope.

Wednesday, June 23, 2010

perlipc in CGI

Sometimes we need start a background process from CGI. When leave that CGI by closing page or window we wish to clean up what we have put in the background. This is perlipc get into role.

There is an example. I have a page displaying a list of network interfaces. I want to get a real time throughput(I/O) chart window when I click on one of these interfaces. Certainly it should be "UP". My solution is forking a poller in background. Poller keeps polling, calculating, and writing data to a shared memory segment. CGI reads from shared memory segment then draws chart for user.



+----------+ fork +------+
|chart page| ----------------> |poller|
+----------+ +------+
| ^
| |
|request |Shared Memory
| |
| +--------+ |
+------> | charter| <------+
+--------+


When click "Close" button on chart page, I need to clean up shared memory and kill the poller. This works fine.

This is the chart page:


...
...

defined (my $pid = fork) or die "Can't fork: $!";

if (!$pid) {
setsid;
open STDIN, '>/dev/null' or die "Can't read from /dev/null: $!";
open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!";
open STDERR, '>/dev/null' or die "Can't write to /dev/null: $!";
exec '/usr/local/NPMS/bin/if_poller.pl', $val->{ip}, $val->{commstring}, $val->{if};
}
...
...

print <<ENDOFFORM;
<script type="text/javascript">
function clean_up() {
document.getElementById('form1').submit();
window.close();
}
</script>
<form id="form1" method="post" action="clean_poller.cgi">
<input name="pid" value="$pid" type="hidden">
<input name="close" value="Close" onclick="clean_up();" type="button">
</form>
ENDOFFORM



This is the clean_poller.cgi:


...
...
kill 'INT' => $in{'pid'};
...
...


This is the poller which trap SIGINT to gracefully exit after clean up resources:


...
...
my $EXIT = 0;
$SIG{INT} = sub {
$EXIT = 1;
};
...
...
while (1) {
...
...
do polling stuff
do {
IPC::Shareable->clean_up_all;
exit;
} if $EXIT;
...
...
}



Let me explain this whole thing:
1. User click one of the active interfaces("UP" state)
2. Open a new window
3. Before display chart, fork a poller
4. poller start to work in background
5. poller write data sample to shared memory segment
6. chart page request charter to draw a chart
7. charter read data sample from shared memory segment and draw
8. User click "Close" button
9. chart page request clean_poller.cgi before closing
10. clean_poller.cgi get pid and send a INT to it
11. clean_poller.cgi close window
12. poller get INT signal, clean up shared memory segment he created
13. poller exit
14. all resources get cleaned up

That's it!

Detail information refer to perlipc, IPC::Shareable, signal, fork, ...

Sunday, June 20, 2010

Permission denied of shmget

When using IPC::Shareable as a non-root user, sometimes got this:


IPC::Shareable::SharedMem: shmget: Permission denied


Just because shared memory is same as regular file. If someone has already created this "file", you can not create it with the same name ($glue) unless your are root.

So, whoever your are, please clean up this shm after you done with it.

(tied VARIABLE)->remove;
IPC::Shareable->clean_up;
IPC::Shareable->clean_up_all;


Refer to: perldoc IPC::Shareable