add per-signal callback data

previously, the callback data was shared by all the signal callbacks.
obviously the last callback set the data for all the callbacks.
It worked because all the signals was actually handled by the
same callback.
factor common code
improve test coverage