Monday, November 08, 2010 at 12:06 AM.

on create () {
		<<5/14/02; 1:51:34 PM by JB
			<<Changelog created.
	<<createIdTable returns the address of a new ID table.
	on mungeId ( idStr ) {
		// this munges the id string into a semaphore name, this scriptlet will be copied into several places.
		if typeOf ( idStr ) == addressType {
			idStr = nameOf ( idStr^ )};
		return "JabberIQTagSem" + idStr};
	local ( idTbl, idName );
	try { // this *shouldn't* need more then 60 ticks to lock
		semaphore.lock("jabberIdTables", 60);;
		idTbl = @system.temp.jabber.idTables["id" +];
		idName = nameOf ( idTbl^ );
		new ( tableType, idTbl );
		idTbl^.expireTime = + 3600}; // one hour
	<<I don't want to document this "publically" (where people might be tempted to fiddle with it, but for you, my loyal reader...
		<<I really like waitForIqReply, because it's relatively subtle code to write from scratch if you're not used to multithreaded programming. Unfortunately, the subtlety interacts poorly with trying to integrate it into the framework, as there's a race condition.
		<<I use a double semaphore lock, with another thread unlocking the semaphore when it's done, to transfer the control around for scripts like jabber.rpc. So you get two scripts:
			<<One that locks a semaphore, then locks the same semaphore in quick succession.
			<<The other thread that unlocks that semaphore when processing is complete, returning control to the other thread.
		<<The problem is that there's a race condition: If the second thread tried to unlock the semaphore before the first thread locks the semaphore at all, it will succeed (it's not an error to unlock nonexistant semaphores), and the first thread will never get a lock on the second semaphore.lock command. Oops. This is easy to make happen, if you get the order of statements wrong.
		<<To prevent this, we lock the semaphore associated with an id table when the id table is created. The delete handler also unlocks it, to prevent pollution of the semaphore table. 
		<<I document this here in such extended form because this is a very subtle place to put this functionality, but after a lot of pondering, I believe this is the best place for it to go.
	semaphore.unlock ( mungeId ( idName ) ); // paranoia
	semaphore.lock ( mungeId ( idName ), 10 );
	return idTbl};
dialog.alert ( create() )

This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.