Thursday 31 January 2013

bash signal handling

A signal trap will not be executed while bash is implicitly waiting for an external command to complete.

I mean:

#! /bin/bash



trap "echo signal" 10
( sleep 1 ; kill -s 10 $$ ) &


sleep 5

We would expect the word signal to be emitted after 1 second, but the signal handler will not run until the sleep 5 is complete.

However, the built-in bash command wait does not have that problem, and so we can run the task in the background and immediately wait as in this example where the signal runs after 1 second.

#! /bin/bash



trap "echo signal" 10
( sleep 1 ; kill -s 10 $$ ) &


<&0 sleep 5 & wait

The <&0 is required to cover the case that the background command needs to read stdin which would otherwise not be connected for a background command.

The script also quits after 1 second even though the sleep is still running, so this variant detects if the background is still running and waits again:

#! /bin/bash



trap "echo signal" 10
( sleep 1 ; kill -s 10 $$ ) &


sleep 5 & wait
kill -s 0 $! &>- && wait

Of course this is insufficient for 2 reasons; the extra wait should be in a loop, but worse, the exit code is lost.

Tuesday 29 January 2013

Poem: The smelly dog-pooh man


I wrote this in early 2008 for the Agbrigg & Belle Vue Community News

The smelly dog-pooh man

© 2008 Sam Liddicott

I'm the smelly dog-pooh man,
I walk around the town,
and leave my smelly dog pooh
where my doggie puts it down.

Not in gutters or in hedges
where no foot will hardly tread,
but the middle of the pavement
there to cake your shoes with dread.

Where the young ones and the old ones
and so many in between,
will spread about my pavement paste
from clumps they hadn't seen.

It's rather hard to miss something
so small and hard to see,
It's also hard to miss it
when its spread so wide and free

So the pushchairs and the children
do a dance around the mess,
that's been spread in pretty patterns –
now the cause of their distress

No-one sees me do it,
though you may observe my work,
or attempts by my apprentices
to spread a little dirt,

and I get a secret pleasure; when–
from behind a mother's door,
I hear the sound of pavement paste
discovered on the floor.

It's not that I'm too lazy
although that's also true,
but I like to punish others
with the things I hate to do.

So I'll leave it on the pavement
and pretend it isn't mine,
Till vengeful neighbours tell on me
and make me pay the fine.

Monday 28 January 2013

gensym and unwind-protect for plain C

I wanted some simple C (I mean gcc's C, of course) version of unwind-protect, a clean-up block that was guaranteed to execute when scope for function finished. And a nice way to express it.

How does this look?

void do_test3() {
  int y=3;
  printf("hello\n");
  scope_cleanup {
    printf("cleaning up %d\n", y);
  }
  { int z=2;
    scope_cleanup { printf("inner cleanup %d\n", z); }
  }
  printf("bye\n");
}

main() {
  do_test3();
}

And when run it emits:

hello
inner cleanup 2
bye
cleaning up 3

Well darn tootin'! And you can have more than one in a function or scope too, without conflict!

How 'tis done

It's only half the story, but of course the heavy lifting is done with gcc's non-standard __attribute((cleanup(...))) which can be appended to any variable definition causing the function whose name is at ... to be called (with a pointer to the variable) when the variable goes out of scope.

Anyone who has used this feature will know how useful (though cumbersome) it is; e.g.

void free_ptr(void* ptr) {
  free(*(void**)ptr);
}
...
void* ptr=malloc(MAX_BUFFER) __attribute((cleanup(free_ptr)));

or

void close_ptr(void* ptr) {
  close(*(int*)ptr);
}
...
int fd =open(path, O_RDONY) __attribute((cleanup(close_ptr)));

But what I really want is to be able to specify is not a function but a clean-up block of code, and not tied to any particular variable, but which is executed when the scope end - like unwind-protect and such,

Something like that can be implemented using this method, but I was looking up nested function definitions in C today (I don't remember why) and I noticed that nested functions can be pre-declared using auto which made it possible to define a macro that would expand to this:

auto void cleanup (void* x);
int cleanup_var __attribute((cleanup(cleanup)));
void cleanup(void* x) ...

Of course the ... isn't part of the definition, it is the point at which a block can be expressed; which will be incorporated into the body of a nested function hastily called cleanup in this example.

Without pre-declaring the cleanup method, the cleanup method must be defined before the variable is declared, making it ugly having to pass the code block as a macro parameter.

gensym

Clearly it is easily possible to over-use the variable name cleanup_var and the function name cleanup simply by doing this more than once per function; what is needed is a way to generate unique symbol names in the C preprocessor.

It isn't possible, sadly (not really! got you there!) because the pre-processor cannot manage counters. But, (thinks I) we all know that a macro expands out to a single line and so one pre-processor symbol that always changes but remains the same for an expansion is __LINE__ (and "that be so" says you)
* see also __COUNTER__

So we have these definitions for gensym

#define GENSYM_CONCAT(name, salt) name ## salt
#define GENSYM2(name, salt) GENSYM_CONCAT(name, salt)
#define GENSYM(name) GENSYM2(name, __LINE__)

And this definition for cleanup (for those that couldn't work it out)

#define scope_cleanup auto void GENSYM(__cleanup__) (void* x); \
int GENSYM(__cleanup_var__) __attribute((cleanup(GENSYM(__cleanup__)))); \
void GENSYM(__cleanup__)(void* x)

of course, I am rather abusing the meaning of gensym by having it return the same name each time... the proper way would be to call gensym once and pass it's result to another macro but that would increase the risk of shadowing existing definitions, for which reason we are using gensym in the first place.

The original example expands out something like:

void do_test3() {
  int y=3;
  printf("hello\n");
  auto void __cleanup_29 (void* x); int __cleanup_var_33 __attribute((cleanup(__cleanup_29))); void __cleanup_29(void* x) {
    printf("cleaning up %d\n", y);
  }
  { int z=2;
    auto void __cleanup_33 (void* x); int __cleanup_var_33 __attribute((cleanup(__cleanup_33))); void __cleanup_33(void* x) { printf("inner cleanup %d\n", z); }
  }
  printf("bye\n");
}


Friday 18 January 2013

A word on Technicalities

I read a comment from a chap who didn't care at all about technicalities but just thought people should pay their share of tax.

He didn't understand that it is the technicalities that make it possible to know what one's share of tax is so that one can pay it.

I think he felt like a benevolent dictator who could whip people into paying their share, but didn't realise the chaos that would ensue when the dictator next to him did the same thing but with a slightly different idea of what the share should be.

It was a sad case of the dangerous liberal dictators which goes like this: "If only everyone would do it my way it would all be so much better and we'd all get along so nicely."

It also reminds me of the more rabid US anti-gun folk who steam away thinking: If only we could MAKE them give up their guns, the country would be more safe and more peaceful; but without realising that they would have to MAKE them like it too, which is no more possible than making the anti-gun chaps like guns.

In other words: We only have these hard conversations because agreement is hard. Yet another attempt to sweep away disagreement isn't going to work.

Technicalities bring peace and order to confusion and disagreement without the need for full agreement.

It is sometimes easier to agree on technicalities than on principle; and that is what politics is, although in politics often the principle is not so much at stake as is who will get the bigger slice of pie.

Re-factoring bash

Sometimes one has to perform maintenance on someone else's bash scripts. At such times one keeps one's mouth shut and gets on with it.

Sometimes one gets to re-write them to add new features, and some re-factoring brings great relief.

See this function wrapper to run a command more than once in case it fails the first time. (Don't get distracted on thoughts of the validity of this approach).

do_cmd()
{
  retval=0
  for i in `seq 1 2`;
  do
    cmd 2>/dev/null $@
    retval=$?
    if [ $retval -eq 0 ];
    then
         break
    fi

    sleep 1
  done

  return ${retval}
}

Can we express that function any more concisely or correctly?

The first thing that comes to mind is local retval=0

...but that is closely followed by the wonder of `seq 1 2` which emits 1 2 and so that line could become:

for i in 1 2

At this point it becomes very obvious that the function will execute cmd up to twice, with a 1 second delay if it fails the first time. Any bash coder given that description could come up with a 1 liner; but let's approach it by degrees.

This chunk:

cmd 2>/dev/null $@
    retval=$?
    if [ $retval -eq 0 ];
    then
         break
    fi

becomes:

cmd 2>/dev/null $@
    retval=$?
    test $retval -eq 0 && break

but we don't need to remember retval if we return right away, so this might become:

cmd 2>/dev/null $@ && return
    retval=$?

(we still remember retval so that we can return the last failure code if the loop exits.

But who needs a loop for 2 iterations? How about this:

do_cmd()
{
  cmd 2>/dev/null $@ && return
  sleep 1
  cmd 2>/dev/null $@
} 

Which is pretty clear. But compare that to a fresh re-write based on the original description above:

do_cmd()
{
  cmd "$@" || sleep 1 && cmd "$@"
} 2>/dev/null

I also added in the missing quotes around $@ and added the stderr redirector to the function body definition.

The function will exit with either 0 because the first invocation succeeds, or it will return with the exit code of the second invocation 1 second later - presuming sleep doesn't fail.

If we are afraid that sleep might fail, we could make the second invocation not dependant on the success of the sleep command:

do_cmd()
{
  cmd "$@" || { sleep 1 ; cmd "$@" ; }
} 2>/dev/null

Of course this doesn't quite match the original function because any stderr resulting from a failure in executing the sleep command would also be hidden.

Friday 11 January 2013

Fix Charging on Acer ZG5

My Acer One ZG5 was not charging for the last year or so. I took it for repair to my local friendly and trusted Wizard Electronics but the chap there was too wise. Armed with the knowledge that it failed to charge two different batteries but yet would boot up under charger power he could conclude quite well that it was not the charger, the connector or the batteries and some troubleshooting on the system board was required. I already knew this of course which was why I took it to him; but he suggested it would be cheaper to replace the main board and a quick look at ebay prices for smashed screen netbooks showed that he was right.

However, to my surprise, while googling to find what the motherboard fault might be I found a clue that it might be (and was!) fixed with a BIOS update!  http://www.acer.com/worldwide/support/download.htm and one version 3110 release later and I was charging both batteries again!

Acer Aspire SD slots on bootup

My jmicron SD card slots not being recognized by Linux Mint unless a card was in the slot when booted. And there were two slots.

early hacks

This post http://ubuntuforums.org/showpost.php?p=10842957&postcount=62 shows a way that works for me to re-scan and detect slots that now have a card in (although the card may need to be removed and re-inserted).

sudo echo 1 > /sys/bus/pci/rescan


Tricks here http://ubuntuforums.org/showpost.php?p=10842957&postcount=62 that use setpci don't work for me, failing to select the device if it isn't already detected, or the pciehp driver which doesn't seem to be present on my installation.

Success

I got auto-detection to work by following these tips https://bugs.launchpad.net/ubuntu/+source/linux/+bug/258446/comments/61 by adding the following files to /etc/modules

pciehp
acpiphp
jmb38x_ms
sdhci-pci
flash_bd
xd_card
jmb38x_xd


rebooting, and running: update-initramfs -u so that those modules would be built in to the ramdisk; and then rebooting again.

Nothing else was required; no use of pciehp, no edit of /etc/default/grub.conf and no creation of files in /etc/modprobe.d/