Wednesday, December 05, 2007

Linux inotify example


#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/inotify.h>

void get_event (int fd, const char * target);
void handle_error (int error);

/* ----------------------------------------------------------------- */

int main (int argc, char *argv[])
{
char target[FILENAME_MAX];
int result;
int fd;
int wd; /* watch descriptor */

if (argc < 2) {
fprintf (stderr, "Watching the current directory\n");
strcpy (target, ".");
}
else {
fprintf (stderr, "Watching %s\n", argv[1]);
strcpy (target, argv[1]);
}

fd = inotify_init();
if (fd < 0) {
handle_error (errno);
return 1;
}

wd = inotify_add_watch (fd, target, IN_ALL_EVENTS);
if (wd < 0) {
handle_error (errno);
return 1;
}

while (1) {
get_event(fd, target);
}

return 0;
}

/* ----------------------------------------------------------------- */
/* Allow for 1024 simultanious events */
#define BUFF_SIZE ((sizeof(struct inotify_event)+FILENAME_MAX)*1024)

void get_event (int fd, const char * target)
{
ssize_t len, i = 0;
char action[81+FILENAME_MAX] = {0};
char buff[BUFF_SIZE] = {0};

len = read (fd, buff, BUFF_SIZE);

while (i < len) {
struct inotify_event *pevent = (struct inotify_event *)&buff[i];
char action[81+FILENAME_MAX] = {0};

if (pevent->len)
strcpy (action, pevent->name);
else
strcpy (action, target);

if (pevent->mask & IN_ACCESS)
strcat(action, " was read");
if (pevent->mask & IN_ATTRIB)
strcat(action, " Metadata changed");
if (pevent->mask & IN_CLOSE_WRITE)
strcat(action, " opened for writing was closed");
if (pevent->mask & IN_CLOSE_NOWRITE)
strcat(action, " not opened for writing was closed");
if (pevent->mask & IN_CREATE)
strcat(action, " created in watched directory");
if (pevent->mask & IN_DELETE)
strcat(action, " deleted from watched directory");
if (pevent->mask & IN_DELETE_SELF)
strcat(action, "Watched file/directory was itself deleted");
if (pevent->mask & IN_MODIFY)
strcat(action, " was modified");
if (pevent->mask & IN_MOVE_SELF)
strcat(action, "Watched file/directory was itself moved");
if (pevent->mask & IN_MOVED_FROM)
strcat(action, " moved out of watched directory");
if (pevent->mask & IN_MOVED_TO)
strcat(action, " moved into watched directory");
if (pevent->mask & IN_OPEN)
strcat(action, " was opened");

/*
printf ("wd=%d mask=%d cookie=%d len=%d dir=%s\n",
pevent->wd, pevent->mask, pevent->cookie, pevent->len,
(pevent->mask & IN_ISDIR)?"yes":"no");

if (pevent->len) printf ("name=%s\n", pevent->name);
*/

printf ("%s\n", action);

i += sizeof(struct inotify_event) + pevent->len;

}

} /* get_event */

/* ----------------------------------------------------------------- */

void handle_error (int error)
{
fprintf (stderr, "Error: %s\n", strerror(error));

} /* handle_error */

/* ----------------------------------------------------------------- */

Monday, September 10, 2007

Just for fun

Everone knows that the points system on Perlmonks is just a bit of fun, but it does give me a warm feeling to login today and get:

You have 20 votes left today.
You gained 15 experience points, isn't that nice?
Congratulations, you have been promoted to Chaplain!
You have 598 points until level 12 - Deacon.

That is from 272 writeups in about a year-and-a-half.

I wish there was a site like perlmonks for PHP!

Friday, August 31, 2007

Parallelism

I have been attending an "Train The Trainer" (TTT) session at Intel in order to teach their new Parallel programming courses. An excellent week, surrounded by some real experts in the field. Several points stand out:

The "free lunch" for developers really is over, and the industry will not know what hit it. Software design and building is about to change, and it will be painful. Strangly, a programmer who had been asleep for 20 years and has suddenly awoke would not see anything new. That programmer might well be better equipped for the multi-core world than those that "kept current". Why? Because the skills practiced then will be even more important now, and the sloppy programming that has become so commonplace will no longer do the job.

Revealing comment:
The lead Intel instructor (an authority on parallel processing) was asked how people who have built everything on OO would cope with parallel processing. The answer was: "They are screwed!".

Now you might say that we have been doing multi-threading for years. Yes, but that is not parallel processing. Multi-threading is usually about splitting I/O tasks: GUI windows, overlapped comms and disk I/O are typical. Parallel processing is about splitting (decomposing) processor tasks, which is a whole new barrel of fish. At least, it is for most people.

This revolution has started, but is not yet in full flow, and won't be for a couple of years. The reason is that there is well enough work for an extra CPU with other processes, like services, and the multi-threading we have right now. The real need willl be with quad and 8 (oct?)-core processors.

Watch this space

Tuesday, July 10, 2007

The real jungle

Just back from teaching Perl in Singapore. The real highlight for me, apart from teaching Perl of course, was the view of the Malaysian jungle on the flight in. The area looks tiny on the map, but it is vast. An amazing place.

I found Singapore to be hot and steamy, and I am talking about the climate. The place has still not shaken off its colonial past. Its own character does come through sometimes, and more power to it. The people seem to be friendly and open without the hang-ups of many large cities. Of course I was only there for a week and I only saw a small part of it.

As usual I looked at scripts that delegates brought in. I have also had a couple of scripts from other people recently. I see very common bad practices regularly:

No use warnings
No use strict
All production scripts should have these set.

Calling subroutines using the & prefix. Why do people do this? Because that is the way we used to do it in perl 4, and people do not update their skills. The & prefix ignores prototype checking, and passes the current value of @_ into the call if no other argument is specified. Don't do it!

Calling external programs instead of Perl built-ins. I have seen `date` used instead of localtime(), `cd $dir`, `pwd`, `mkdir`, `rm`, `egrep`, and so on. This is not just lazy, it is grossly inefficient. It is also a security risk, by the way. I published a list of UNIX commands and perl equivalents, I will try and update it soon.

Monday, June 25, 2007

The threading jungle

Multi-threading has been around a long time. I first heard the term in the mid-1980s when discussing how ICL were going to host UNIX on VME. The first real implementation I saw was on Apollo NCS, a system that had many innovative features. ICL, VME, and Apollo have all gone, victims of acquisitions. Threads remain.

Multi-threading hit the mainstream with Windows NT, the system was built on it. The consensus around us UNIX hackers was that Microsoft had to encourage threads because their processes were so inefficient - no fork/exec you see. Probably utter twaddle; you know what UNIX hackers are.

Threads brought synchronisation problems. Of course they did. System programmers were no strangers to this type of issue, just the context of threads was new(ish). Way back when, on ICL VME, all we had were "test and set" and "decrement and set" instructions that were atomic. When I were a lad we had to build our own primitives, there was a particularly handy instruction that let you not only raise an interrupt (event/signal, whatever) but allowed you to send a two-word data block with it. Kids of today … don't know they're born… forty miles 't pit… etc.

I got to write real synchronisation primitives when I did the VME port of the MIMER RDBMS in the early '80s. There is nothing like having to write the damn things to understand how they work. I did not design them, I hastily add - that was done by some egg-head at Uppsala University. The problem then, as now, is not in using the APIs, it is in understanding how they interact with your application and (more important) how the application interacts with itself.

First rule when writing co-operating threads: things only go wrong at the worse possible moment. And that is usually after the thing has gone into production.

The Windows APIs are fairly easy to use, certainly compared to knitting your own. The main wrinkles in using them are a few peculiarities with the C/C++ runtime-library. I find it amazing that so many system engineers insist in using CreateThread instead of _beginthreadex. Back in Visual Studio 2.0 this was understandable, even I did it. The documentation was, um, "challenged". Now, with the MSDN, there is no excuse, the problems are well documented. Still people insist on using the wrong API. My theory, for what it is worth, is that a call to _beginthreadex, with its associated casts, looks messy on the screen, surrounded as it is by unrivalled elegance (sic). CreateThread looks good, _beginthreadex is ugly. For wotsit's sake! A thing of beauty with a memory leak is bad code, and I don't care what it looks like. Humph.

Still, you thought that was ugly? Try finding the thread-safe RTL functions in pthreads. Threads had to be retro-fitted to UNIX. Many fought against it, even the hero Torvold in the clone wars, but resistance was futile. Microsoft made life easy for us developers by having a whole special runtime-library just for multi-threading, ungrateful pups that we are. The pthreads implementations on UNIX have no such luxury. Instead there is a whole mess of different functions that are re-entrant with the _t suffix. Bye-bye portability. Finding which functions these are is a bit hit and miss, sometimes they are not in the man pages, and the standard only lists minimum requirements. Try teaching Condition Variables to a class already spaced out by mutxes. The word "predicate" makes their eyes glaze over. The fixed grin is the give-away: "Gone, solid gone", as Baloo would say. I'm sure Kipling was a coder, who else would write a whole poem about a conditional statement?


Wednesday, May 30, 2007

What I did on my holiday

1. Read "Perl Hacks" again, and caught a bunch of stuff I had missed first time around. Like, wantarray returns undef in void context.

2. Read "Parallel Programming in C with MPI and OpenMP" by Michael J. Quinn
Very American (the first computer was ENIAC - really?) No mention of the ICL DAP (Distributed Array Processor) - one of the first commercially available parallel processors.
Nice to see terms like "Functional Decomposition" from the 1970s recycled to be used in a parallel computing methodology.
It really bugs me when authors come up with "Creating Arrays at Run Time" and give code like this:
int *A;
A = (int *) malloc (n * sizeof(int));
When there is a perfectly good feature in C99 to do it:
int A[n];
That's it! This is a C99 Variable Length Array, one of the more obvious features of the changes from C89. The book was published in 2004, so why no mention?
The author uses for loops to access arrays quite often, but there is no mention of optimisers, and the effect of optimisations on parallel processing. Ho hum.

Thursday, April 05, 2007

Where have you been?

Guilty. I haven't blogged for a long time.

What's happened?
Well for starters the company I work for got taken over, and that caused a lot of dust - mostly settled now.

I have been getting into the new Korn shell 93, and I hope to post something on that soon.

Just today I got my "Happy Monkday" from perlmonks - I have been a monk for a year. Good fun!

Oh where is Perl 5.10? Soon? Please!