This weekend I spent a bit of time playing with Squeak (as my non-commercial Gemstone/S was missing a valid license key, so the plan to play with that went out the window).
Starting simply, I tried the following, based on some example code:
HTTPSocket httpShowPage: 'http://www.darrenhobbs.com/index.html'
Sure enough, up popped a window with the raw html of my homepage.
Wanting to try out multiple requests, I modified the code to this:
10 timesRepeat:[HTTPSocket httpShowPage: 'http://www.darrenhobbs.com/index.html'].
After a significant pause, 10 windows appeared one after the other. This was probably due to the 10 connections being single threaded and run one at a time. I then tried this:
10 timesRepeat:[[HTTPSocket httpShowPage: 'http://www.darrenhobbs.com/index.html'] fork].
It took about the same amount of time, but the windows started coming back quicker.
Being ambitious, I then tried the following:
100 timesRepeat:[[HTTPSocket httpShowPage: 'http://www.darrenhobbs.com/index.html'] fork].
And all hell broke loose. Major UI corruption. Turns out that HTTPSocket::httpShowPage is not thread safe, and updating the UI from more than one thread is a bad idea. This is fair enough – the method is basically a helper that pops a window with the contents of a url.
The offending line was this one in HTTPSocket::showPage
(StringHolder new contents: doc) openLabel: url.
Wanting a quick way to make it work for me, I went on a hunt for mechanisms to ensure thread safe UI updating and found this method on WorldState:
WorldState addDeferredUIMessage:
Changing the line in httpShowPage like so:
WorldState addDeferredUIMessage:[(StringHolder new contents: doc) openLabel: url].
And all was well. Now the multiple forked requests to httpShowPage would queue up their UI updates and play nicely together.
But thats not quite the end of the story. I now had 100 windows open, all showing the raw html from my homepage, that I had to get rid of. I could have clicked on each one individually, but I’m a developer, and this is Squeak, so after much experimentation, I came up with this:
| holders darrens | holders := SystemNavigation default allObjectsSelect:[:anObject | anObject class = SystemWindow]. darrens := holders select:[:each | each label = 'http://www.darrenhobbs.com/index.html']. darrens do: [:each | each delete].
And presto, 100 windows deleted.
The moral being that a system that describes itself and written in itself and is open to change is hugely powerful, and very pleasing to work with.