Tinkerer’s Closet – Selecting hardware

Well, there’s no better reason to clean out your closet or workspace, than to fill it with new stuff!! I’ve been spending a fair amount of time cleaning out the old stuff, and I’ve gotten far enough along that I feel it’s safe to poke my head up and see what’s new and exciting in the world of hardware components today.

What to look at though, so I don’t just fill up with a bunch more stuff that doesn’t get used for the next 10 years? Well, this time around I’m going project based. That means, I will limit my searching to stuff that can help a project at hand. Yes, it’s useful to get some items just for the learning of it, but for a hoarder, it’s better to have an actual project in mind before making purchases.

On the compute front, I’ve been standardizing the low end around ESP 32 modules. I’ve mentioned this in the past, but it’s worth a bit more detail. The company, Espressif, came along within the past decade, and just kind of took the maker community by storm. Low cost, communications built in (wifi, bluetooth), capable processors (32-bit). They are a decent replacement at the low end of things, taking the place of the venerable Arduino, which itself was a watershed in its day.

The keen thing about the Espressif modules is how programmable they are. You can use the Aruino IDE, or PlatformIO (tied to Visual Studio), or their standalone IDE. You can program it like a single CPU with full control of everything, or you can run a Real-time OS (FreeRTOS) on it. This makes it super easy to integrate into anything from simple servo motor control, to full on robotics.

As for form factor, I’m currently favoring the Adafruit ‘feather’ forms. The ‘feather’ form factor is a board specification, which puts pins in certain locations, regardless of which actual processor is on the board. This makes it a module that can be easily integrated into designs, because you have known patterns to build around. I have been using the ESP32 Feather V2 primarily.

It’s just enough. USB-C connector for power, and programming. Battery connector for easy deployment (battery charges when USB-C is plugged in). STEMMA QT connector (tiny 8 pin connector) for easy I2C connection of things like joysticks, sensors, anything on the I2C bus. Antenna built in (wifi/bluetooth radio on the right, with black PCB antenna next to it).

It’s just a handy little package, and my current best “computicle”. You can go even smaller, and get ESP 32 modules in different packages, but this is the best for prototyping in my lab.

As an aside, I want to mention Adafruit, the company, as a good source for electronic components. You can checkout their about page to get their history. Basically, they were created in 2005, and have been cranking out the hits in the maker space ever since. What attracted me to them initially was their tutorials on the components they sell. They have kits and tutorials on how to solder, as well as how to integrate motors into an ESP 32 design. Step by step, detailed specs, they’re just good people. They also pursue quality components. I mean, every USB cable is the same right? Nope, and they go through the myriad options, and only sell the best ones. So, if you’re in the market, check them out, at least for their tutorials.

Going up the scale from here, you have “Single Board Computers”. The mindshare leader in this space is definitely the Raspberry Pi. When they sprung onto the scene, there really wasn’t any option in the sub-$50 range. Since then (2006ish), there has been an entire renaissance and explosion of single board computers. They are typically characterized by: Arm based processor, 4-8Gb RAM, USB powered, HDMI output, a couple of rows of IO pins, running Linux (Ubuntu typically).

I’ve certainly purchased my share of Raspberry Pi boards, and variants. I tend to favor those coming from Hard Kernel. I find their board innovations over the years to be better than what the Pi Foundation is typically doing. Also, they are more readily available. Hard Kernel has commercial customers that use their boards in embedded applications, so they tend to have Long Term Support for them. They have boards based on ARM typically, meant to run Linux, but they also have Windows based boards as well.

Here’s a typical offering,

The Odroid M1S.

The one thing that’s critical to have in a single board computer is software support. There are as many single board computers available in the world as there are grains of sand on a beach. What differentiates them is typically the software support, and the community around it. This is why the Raspberry Pi has been so popular. They have core OS support, and a super active community that’s always making contributions.

I find the Odroid boards to be similar, albeit a much smaller community. They do have core OS support, and typically get whatever changes they make integrated into the mainline Linux development tree.

This M1S I am considering as a brain for machines that need more than what the ESP32 can handle. A typical situation might be a CNC machine, where I want to have a camera to watch how things are going, and make adjustments if things are out of wack. For example, the camera sees that the cutting bit has broken, and will automatically stop the machine. Or, it can see how the material is burring or burning, and make adjustments to feeds and speeds automatically.

For such usage, it’s nice to have the IO pins available, but communicating over I2C, CANBus, or other means, should be readily available.

This is reason enough for me to purchase one of these boards. I will look specifically for pieces I can run on it, like OpenCV or some other visual module for the vision stuff. I have another CNC router that I am about to retrofit with new brains, and this could be the main brain, while the ESP32 can be used for the motor control side of things.

Last is the dreamy stuff.

The BeagleV-Fire

This is the latest creation of BeagleBoard.org. This organization is awesome because they are dedicated to creating “open source” hardware designs. That’s useful to the community because it means various people will create variants of the board for different uses, making the whole ecosystem more robust.

There are two special things about this board. One is that it uses a RISC-V chip, instead of ARM. RISC-V is an instruction set, which itself is open source, and license free. It is a counter to the ARM chips, which have license fees and various restrictions. RISC-V in general, will likely take up the low end of the market for CPU processors in all sorts of applications that typically had ARM based chips.

The other feature of these boards is onboard integrated FPGA (Field Programmable Gate Array). FPGA is a technology which makes the IO pins programmable. If you did not have a USB port, or you wanted another one, you could program some pins on the chip to be that kind of port. You can even program a FPGA to emulate a CPU, or other kinds of logic chips. Very flexible stuff, although challenging to program.

I’ve had various FPGA boards in the past, and even ones that are integrated with a CPU. This particular board is another iteration of the theme, done by a company that has been a strong contributor in the maker community for quite some time.

Why I won’t buy this board, as much as I want to; I don’t have an immediate need for it. I want to explore FPGA programming, and this may or may not be the best way to learn that. But, I don’t have an immediate need. Getting an Odroid for creating a smarter CNC makes sense right now, so one of those boards is a more likely purchase in the near term. It might be that in my explorations of CNC, I find myself saying “I need the programmability the BeagleBone has to offer”, but it will be a discovery based on usage, rather than raw “I want one!”, which is a departure from my past tinkerings.

At this point, I don’t need to explore above Single Board computers. They are more than powerful enough for the kinds of things I am exploring, so nothing about rack mountable servers and kubernetes clusters.

At the low end, ESP32 as my computicles. At the high end, Hard Kernel based Single Board Computers for brains.


Tinkerer’s Closet – Hardware Refresh

I am a tinkerer by birth. I’ve been fiddling about with stuff since I was old enough to take a screwdriver off my dad’s workbench. I’ve done mechanical things, home repair, wood working, gardening, 3d printing, lasering, just a little bit of everything over the years. While my main profession for about 40 years has been software development, I make the rounds through my various hobbies on a fairly regular basis.

Back around 2010, it was the age of 3D printers, and iOT devices. I should say, it was the genesis of those movements, so things were a little rough. 3D printers, for example, are almost formulaic at this point. Kits are easily obtained, and finished products can be had for $300-$400 for something that would totally blow away what we had in 2010.

At that time, I was playing around with tiny devices as well. How to make a light turn on from the internet. How to turn anything on, from a simple radio controller. As such, I was into Arduino microcontrollers, which we making the rounds of popularity, and much later, the Raspberry Pi, and other “Single Board Computers”. There were also tons of sensor modules (temperature, accelerometers, light, moisture, motion, etc), and little radio transmitters and receivers. The protocols were things like Xigbee, and just raw radio waves that could be decoded to ASCII streams.

As such, I accumulated quite a lot of kit to cover all the bases. My general moto was; “Buy two of everything, because if one breaks…”

The purchasing playground for all this kit was limited to a few choice vendors. In the past it would have been Radio Shack and HeathKit, but in 2010, it was:

AdaFruit

SeeedStudio

SparkFun

There were myriad other creators coming up with various dev boards, like the low power JeeLabs, or Dangerous Prototypes and their BusPirate product (still going today). But, mostly their stuff would end up at one of these reliable vendors, along with their own creations.

Lately, and why I’m writing this missive, I’ve been looking at the landscape of my workshop, wanting to regain some space, and make space for new projects. As such, I started looking through those hidey holes, where electronics components tend to hide, and hang out for generations. I’ve started going through the plastic bins, looking for things that are truly out of date, no longer needed, never going to find their way into a project, no longer supported by anyone, and generally, just taking up space.

To Wit, I’ve got a growing list of things that are headed for the scrap heaps;

433Mhz RF link kit, 915Mhz RF Link Kit, Various versions of Arduinos, Various versions of Raspberry Pi, TV B Gone KIt (built one, tossing the other, maybe save for soldering practice for the kids), Various Xigbee modules, Parallax Propellar (real neat stuff), SIM Card Reader, Gadget Factory FPGA boards and wings, trinkets, wearables, and myriad other things either as kits, boards, and what have you.

I’m sad to see it go, knowing how lovingly I put it all together over the years. But, most of that stuff from from 13 years ago. Things have advanced since then.

It used to be the “Arduino” was the dominant microcontroller and form factor for very small projects. Those boards could run $30, and weren’t much compared to what we have today. Nowadays, the new kids in town are the ESP 32 line of compute modules, along with form factors such as the Adafruit supported “Feather”. A lot of the modules you used to buy separate, like Wifi, are just a part of the chip package, along with BlueTooth. Even the battery charging circuitry, which used to be a whole separate board, is just a part of the module now. I can buy a feather board for $15, and it will have LiPo charging circuitry, USB-C connectivity for power and programming, Wifi (abgn), and BlueTooth LE. The same board will have 8 or 16Mb or RAM, and possibly even dual cores! That’s about $100 worth of components from 2010, all shrunken down to a board about the size of my big thumb. Yes, it’s definitely time to hit refresh.

So, I’m getting rid of all this old stuff, with a tear in my eye, but a smile on my face, because there’s new stuff to be purchased!! The hobby will continue.

I’m happily building new machines, so my purchases are more targeted than the general education I was pursuing back then. New CPUs, new instructions sets, new data sheets, new capabilities, dreams, and possibilities. It’s both a sad and joyous day, because some of the new stuff at the low end even has the words “AI Enabled” on it, so let’s see.


Embodied AI – Software seeking hardware

The “AI” space writ large, covers an array of different topics. At this moment in time, the Large Language Models (LLMs) have captured everyone’s imagination, due to their uncanny ability to give seemingly good answers to a number of run of the mill questions. I have been using ChatGPT specifically for the past year or so, and have found it to be a useful companion for certain tasks. The combination I use is GitHub Copilot, in my Visual Studio development environment, and ChatGPT on the side. Copilot is great for doing very sophisticated copy and paste based on comments I type in my code. ChatGPT is good for exploring new areas I’m not familiar with, and making suggestions as to things I can try.

That’s great stuff, and Microsoft isn’t the only game in town now. Google with their Bard/Gemini is coming right along the same path, and Facebook isn’t far behind with their various llama based offerings. I am currently exploring beyond what the LLM models provide.

One of the great benefits I see of AI is the ability to help automate various tasks. Earlier in the 20th century, we electrified, and motorized a lot of tasks, which resulted in the industrial revolution, giving us everything from cars to tractors, trains, airplanes, and rockets. Now we sit at a similar nexus. We have the means to not just motorize everything, but to give everything a little bit of intelligence as well. What I’m really after in this is the ability to create more complex machines, without having to spend the months and years to develop the software to run them. I want them to ‘learn’. I believe this can make the means of production of goods accessible to a much broader base of the population than ever before.

What I’m talking about is manufacturing at the speed of thought. A facility where this is done is a manufactory.

In my idealized manufactory, I have various semi-intelligent machines that are capable of learning how to perform various tasks. At a high level, I want to simply think about, and perhaps visualize a piece of furniture, turn to my manufactory and say “I need a queen sized bed, with four posts, that I can assemble using a screwdriver”. What ensues is what you might expect from a session with ChatGPT, a suggestion of options, some visualization with some sort of Dall-E piece, and ultimately an actual plan that shows the various pieces that need to be cut, and how to assemble them. I would then turn these plans over to the manufactory and simply say “make it so”, and the machinery would spring into life, cutting, shaping, printing, all the necessary pieces, and delivering them to me. Bonus if there is an assembly robot that I can hire to actually put it together in my bedroom.

Well, this is pure fantasy at this moment in time, but I have no doubt it is achievable. To that end, I’ve been exploring various kinds of machines from first principles to determine where the intelligence needs to be placed in order to speed up the process.

I am interested in three kinds of machines

CNC Router – Essentially a router, or spindle, which has a spinning cutting bit. Typically rides on a gantry across a flat surface, and is capable of carving pieces.

3D Printer – Automated hot glue gun. The workhorse of plastic part generation. Basically a hot glue gun mounted to a tool head that can be moved in a 3D space to additively created a workpiece.

Robotic Arm – Typically with 5 or 6 joints, can have various tools mounted to the end. Good for many different kinds of tasks from welding, to picking stuff up, to packing items into a box.

There are plenty of other base machines, including laser cutters, milling machines, lathes, and presses, but I’ve chosen these three because they represent different enough capabilities, but they’re all relatively easy to build using standard tools that I have on hand. So, what’s interesting, and what does AI have to do with it?

Let’s look at the 3D Printer.

the100 – This is a relatively small 3D printer where most of the parts are 3D printed. The other distinction is holds is that it’s super fast when it prints, rivaling anything in the consumer commercial realm. The printability is what drew me to this one because that means all I need to start is another relatively inexpensive ($300) 3D printer to start. And of course once the100 is built, it can 3D print the next version, even faster, and so on and so forth.

The thing about this, and all tools, is they have a kinematic model. That is, they have some motors, belts, pulleys, etc. Combined, these guts determine that this is a machine capable of moving a toolhead in a 3D space in a certain way. I can raise and lower the print bed in the Z direction. I can move the tool head in the XY direction. The model also has some constraints, such as speed limits based on the motors and other components I’m using. There’s also constraints as to the size of the area within which it can move.

The way this is all handled today is clever people come up with the programs that tie all this stuff together. We hard code the kinematic model into the software, and run something like Klipper, or Marlin, or various others, which take all that information, are fed a stream of commands (gcode), and know how to make the motors move in the right way to execute the commands.

There is typically a motherboard in these machines that has a combination of motor control and motion control, all wrapped up in a tight package.

I want to separate these things. I want motor control to be explicit, and here I want to inject a bit of AI. In order to ’embody’ AI, I need to teach a model about it’s kinematics. From there, I want to train it on how to move based on those kinematics. I don’t want to write the code telling it every step how to move from point A to B, which is what we do now. I want to let it flop around, giving it positive re-enforcement when it does the right thing, and negatives when it doesn’t. Just like we do with cars, just like we do with characters in video games. This is the first step of embodiment. Let the machine know its senses and actuators, and encourage it to learn how to use itself to perform a task.

Basic motor control is something the model needs to be told, as part of the kinematic model. Motion control is the next level up. Given a task, such as ‘draw a curved line from here to there’, which motors to engage, for how long, in which sequence, when to accelerate, how fast, how long, best deceleration curve, that’s all part of the motion control, and something a second level of intelligence needs to learn.

On top of all that, you want to layer an ability to translate from one domain to another. As a human, or perhaps another entity in the manufacturing process, I’m going to hand you a ‘.stl’ or ‘.step’ or various other kinds of design files. You will then need to translate that into the series of commands you understand you can give to your embodied self to carry out the task of creating the item.

But, it all starts down in motor control, and kinematic modeling.

Next up is the CNC Router

This is the lowrider 3 by V1 Engineering. What’s special here again is the ease of creating the machine. It has mostly 3D printed parts, and used standard components that can be found at a local hardware store. At it’s core is a motor controller, which is very similar to the ones used in the 3D printer case. Here again, the machine is running in a pretty constrained 3D space, and the motor control is very similar to that of the 3D printer. These two devices run off different motherboards, but I will be changing that so they essentially run with the same brain when it comes to their basic motor control and kinematic understanding.

Whereas the 3D printer is good for small parts (like the ones used to construct this larger machine), the CNC router, in this case, is good for cutting and shaping of sheet goods, like large 4ftx8ft sheets of playwood for cabinet and furniture making. Giving this platform intelligence gives us the ability to send it a cut list for a piece of furniture and have it figure that out and just do it.

Of course, these capabilities exist in larger industrial machines, that have typically been programmed, and are tied to CAD/CAM software. Here though, I’m after something different. I don’t want to “program” it, I want to teach it, starting from the base principles of its own kinematics.

Last is the venerable Robot Arm

Here, I am building a version of the AR4 MK2 robot arm from Annin Robotics

This machine represents a departure from the other two, with 6 degrees of freedom (shoulder, elbow, wrist, etc). The motors are larger than those found in the 3D printer or CNC router, but how to control and sense them is relatively the same. So, again, ultimately I want to separate sense and motor control from motion control. I will describe a kinematic model, and have the bot learn how to move itself based on reinforcement learning on that model.

All of this is possible now because of the start of the technology. Microcontrollers, or very small computers, are more than capable of handling the complex instructions to control a set of motors. This is a departure from just 10 years ago when I needed a complete real-time Linux PC with a parallel port to control the motors alone. Now I can do it with an esp32 based device that costs less than $20, and can run off a hobby battery. Similarly, the cost of ‘intelligence’ keeps dropping. There are LLMs such as llama.cpp which can run on a Raspberry pi class machine, which can be easily incorporated into these robot frames.

So, my general approach to creating the manufactory is to create these robot frames from first principles, and embody them with AI as low as we can go, then build up intelligence from there.

At this time, I have completed the AR4 arm, and the Lowrider CNC. the100 printer is in progress, and should complete in a couple of weeks. Then begins the task of creating the software to animate them all, run simulations, train models, and see where we get to.


Have Computicles Arrived?

So, I’ve written quite a lot about computicles over the past few years.  In most of those articles, I’m talking about the software implementation of tiny units of computation.  The idea for computicles stems from a conversation I had with my daughter circa 2007 in which I was laying out a grand vision of the world where units of computation would be really small, fit in your hand sized, and be able to connect and do stuff fairly easily.  That was my envisioning of ubiquitous computing.  And so, yesterday, I received the latest creation from HardKernel, the Odroid HC1 (HC – Home Cloud).

20170902_072503

Hardkernel is a funny company.  I’ve been buying at least one of everything they’ve made in the past 5 years or so.  They essentially make single board computers in the “credit card” form factor.  What you see in the picture is the HC1, with an attached SSD of 120Gb.  The SSD is 2.5″ standard, so that gives you a sense of the size of the thing.  The black is aluminum, and it’s the heat sink for the unit.

The computer bit of it is essentially a reworked Odroid XU4, which all by itself is quite a strong computer in this category.  Think Raspberry Pi, but 4 or 5 times stronger.  The HC1 has a single Sata connector to slot in whatever hard storage you choose.  No extra ribbon cables or anything like that.  The XU4 itself can run variants of Linux, as well as Android.  The uSD card sticking out the right side provides the OS.  In this particular case I’m using OMV (Open Media Vault), because I wanted to try the unit out as a NAS in my home office.

One of the nice things about the HC1 is that it’s stackable.  So, I can see piling up 3 or 4 of these to run my local server needs.  Of course, when you compare to the giant beefy 64-bit super server that I’m currently typing at, these toy droids give it very little competition in the way of absolute compute power.  They even did an analysis of bitcoin mining and determined a number of years it would take to get a return on their investment.  But, computing, and computicles aren’t about absolute concentrated power.  Rather, they are about distributed processing.

Right now I have a Synology, probably the equivalent of today’s DS1517.  That thing has RAID up the wazoo, redundant power, multiple nics, and it’s just a reliable workhorse that just won’t quit, so far.  The base price starts at $799, before you actually start adding storage media.  The HC1 starts at $49.  Of course there’s no real comparison in terms of reliability, redundancy, and the like, or is there?

Each HC1 can hold a single disk.  You can throw on whatever size and variety you like.  This first one has a Samsung SSD that’s a couple years old, at 120Gb.  These days you can get 250Gb for $90.  You can go up to 4TB with an SSD, but that’s more like a $1600 proposition.  So, I’d be sticking with the low end.  That makes a reasonable storage computicle roughly $150.

You could of course skip the SSD or HDD and just stick a largish USB thumb drive, or 128Gb uSD for $65, but the speed on that interface isn’t going to be nearly as fast as the Sata III interface the HC1 is sporting.  So, great for a small time use, but for relatively constant streaming and download, the SSD solutions, and even HDD solutions will be more robust.

So, what’s the use case?  Well, besides the pure geekery of the thing, I’m trying to imagine more appliance like usage.  I’m imagining what it looks like to have several of these placed throughout the house.  Maybe one is configured as a YouTube downloader, and that’s all it does all the time, shunting to the larger Synology every once in a while.

How about video streaming?  Right now that’s served up by the Synology running a Plex server, which is great for most clients, but sometimes, it’s just plain slow, particularly when it comes to converting video clips from ancient cameras and cell phones.  Having one HC1 dedicated to the task of converting clips to various formats that are known to be used in our house would be good.  Also, maybe serving up the video itself?  The OMV comes with a minidlna server, which works well with almost all the viewing kit we have.  But, do we really have any hiccups when it comes to video streaming from the Synology?  Not enough to worry about, but still.

Maybe it’s about multiple redundant distributed RAID.  With 5 – 10 of these spread throughout the house, each one could fail in time, be replaced, and nothing would be the wiser.  I could load each with a couple of terabytes, and configure some form of pleasant redudancy across them and be very happy.  But, then there’s the cloud.  I actually do feel somewhat reassured having the ability to backup somewhere else.  As recent flooding in Texas shows, as well as wildfires, no matter how much redundancy you have locally, it’s local.

Then there’s compute.  Like I said, a single beefy x64 machine with a decent GPU is going to smoke any single one of these.  Likewise if you have a small cluster of these.  But, that doesn’t mean it’s not useful.  Odroid boards are ARM based, which makes them inherently low power consumption compared to their intel counterparts.  If I’ve have some relatively light loads that are trivially parallelizable, then having a cluster of a few of these might make some sense.  Again with the ubiquitous computing, if I want to have the Star Trek style “computer, where’s my son”, or “turn on the lights in the garage”, without having to send my voice to the cloud constantly, then performing operations such as speech recognition on a little cluster might be interesting.

The long and short of it is that having a compute/storage module in the $150 range makes for some interesting thinking.  It’s surely not the only storage option in this range, but the combination of darned good hardware, tons of software support, low price and easy assembly, gives me pause to consider the possibilities.  Perhaps the hardware has finally caught up to the software, and I can start realizing computicles in physical as well as soft form.


schedlua – async io

And so, finally we come to the point. Thus far, we looked at the simple scheduler, the core signaling, and the predicate and alarm functions built atop that. That’s all great stuff for fairly straight forward apps that need some amount of concurrency. The best part though is when you can do concurrent networking stuff.

Here’s the setup; I want to issue 20 concurrent GET requests to 20 different sites, and get results back. I want the program to halt once all the tasks have been completed.

--test_linux_net.lua
package.path = package.path..";../?.lua"

local ffi = require("ffi")

local Kernel = require("kernel"){exportglobal = true}
local predicate = require("predicate")(Kernel, true)
local AsyncSocket = require("AsyncSocket")

local sites = require("sites");

-- list of tasks
local taskList = {}


local function httpRequest(s, sitename)
	local request = string.format("GET / HTTP/1.1\r\nUser-Agent: schedlua (linux-gnu)\r\nAccept: */*\r\nHost: %s\r\nConnection: close\r\n\r\n", sitename);
	return s:write(request, #request);
end

local function httpResponse(s)
	local BUFSIZ = 512;
	local buffer = ffi.new("char[512+1]");
	local bytesRead = 0
	local err = nil;
	local cumulative = 0

	repeat
		bytesRead, err = s:read(buffer, BUFSIZ);

		if bytesRead then
			cumulative = cumulative + bytesRead;
		else
			print("read, error: ", err)
			break;
		end
	until bytesRead < 1

	return cumulative;
end


local function siteGET(sitename)
	print("siteGET, BEGIN: ", sitename);

	local s = AsyncSocket();

	local success, err = s:connect(sitename, 80);  

	if success then
		httpRequest(s, sitename);
		httpResponse(s);
	else
		print("connect, error: ", err, sitename);
	end

	s:close();

	print("siteGET, FINISHED: ", sitename)
end


local function allProbesFinished()
	for idx, t in ipairs(taskList) do
		if t:getStatus() ~= "dead" then
			return false;
		end
	end

	return true;
end

local function main()
	for count=1,20 do
		table.insert(taskList, Kernel:spawn(siteGET, sites[math.random(#sites)]))
		Kernel:yield();
	end

	when(allProbesFinished, halt);
end

run(main)

Step by step. The httpRequest() function takes a socket, and does the most bare mimimal HTTP GET request, assuming the socket is already connected to the site.

Similarly, the httpResponse() function gets a response back from the server, and reads as much as it can until the socket is closed (because the Connection: close header was sent).

That’s about the most basic of HTTP request/response pairs you can have, ignoring doing any parsing of the returned data.

Alright, so let’s wrap those two up into a function called siteGET(). siteGET(sitename) takes the name of a site, creates a socket, connects it to the site, and then issues the httpRequest(), and then the httpResponse(). Very simple. What I like about this is that the httpRequest(); httpResponse() sequence is executed in serial as far as I’m concerned. I don’t have to be worried about the httpResponse() being issued before the request completes. Furthermore, if I didn’t use a spawn(), I could simply execute the code directly and be none the wiser.

I want to execute these siteGET()s concurrently though, so within main(), I start up 20 of these tasks, and let them go. Then comes the waiting part:

local function allProbesFinished()
	for idx, t in ipairs(taskList) do
		if t:getStatus() ~= "dead" then
			return false;
		end
	end

	return true;
end

	when(allProbesFinished, halt);

Going back to our knowledge of predicates, we know that the ‘when’ function takes a predicate (function that returns true/false), and will execute the second function when the predicate returns true.

OK, so we just need to come up with a predicate which tells us that all the tasks have completed. Easy enough as a list of the tasks is generated when they are spawned. So, we just go through that list and see if any of them are still running. If there is a single one that is still running, the predicate will return false, and ‘halt()’ will not be called. As soon as the last task finished, the predicate will return true, and the halt() function will be called.

Of course, most things in schedlua are convenient compositions of deeper things (with signals being at the core).

Instead of using the ‘when’ function, you could write the code more directly like this:

	while true
		if allProbesFinished() then
			halt();
			break;
		end
		yield();
	end

That doesn’t quite look as nice as just using the when() function I think. Also, you’re sitting in the main() function, which is no big deal as there’s nothing else trying to execute after this, but it just doesn’t seem as clean. Furthermore, the ‘when’ function might have some magic in its implementation, such as a better understanding of the state of tasks, or special knowledge of the scheduler, or who knows what. At any rate, either way essentially implements a barrier, and the technique can be used anywhere you want to perform an action after some set of tasks has completed. The allProbesFinished() function can be generalized to wait on any list of tasks, maybe call it “waitForTasks()” or some such thing.

At any rate, that completes the primitives that are baked into the core schedlua package. Everything from signals, to predicates, alarms, and finally async io. Of course this is Linux, so async io works with any file descriptor, not just network sockets, so file management or device communications in general can be thrown into the mix.

Now that the basics work, it’s a matter of cleaning up, writing more test cases, fixing bugs, reorganizing, and optimizing resource usage a bit. In general though, the constructs are there, and it’s ready to be used for real applications.


schedlua – predicates and alarms

A few years back, during the creation of Language Integrated Query (LINQ), I had this idea. If we could add database semantics to the language, what would adding async semantics look like. These days we’ve gone the route of async/await and various other constructs, but still, I always just wanted a primitives. such as “when”, “whenever”, and “waitUntil”. The predicates in schedlua are just that:

  • signalOnPredicate(predicate, signalName)
  • waitForPredicate(predicate)
  • when(predicate, func)
  • whenever(predicate, func)

Of courese, this is all based at the very core on the signaling mechanism that’s in the kernel of schedlua, but these primitives are not in the kernel proper.  They don’t need to be, which is nice because it means you can easily add such functions without having to alter the core.

What do they look like in practice?  Well, first of all, a ‘predicate’ is nothing more than a fancy name for a function that returns a bool value.  It will either return ‘true’ or ‘false’.  Based on this, various things can occur.  For example, ‘signalOnPredicate’, when the predicate returns ‘true’, emit the signal specified by signalName.  Similarly, for ‘waitForPredicate’, the currently running task will be put into a suspended state until such time as the predicate returns ‘true’.  ‘when’ and ‘whenever’ are similar, but they spawn new tasks, rather than suspending the existing task.  And here’s some code:

 

--test_scheduler.lua
package.path = package.path..";../?.lua"

local Functor = require("functor")
local Kernel = require("kernel"){exportglobal = true}
local Predicate = require("predicate")(Kernel, true)

local idx = 0;
local maxidx = 100;

local function numbers(ending)
	local function closure()
		idx = idx + 1;
		if idx > ending then
			return nil;
		end
		return idx;
	end
	
	return closure;
end



local function counter(name, nCount)
	for num in numbers(nCount) do
		print(num)
		local eventName = name..tostring(num);
		--print(eventName)
		signalOne(eventName);

		yield();
	end

	signalAll(name..'-finished')
end


local function predCount(num)
	waitForPredicate(function() return idx > num end)
	print(string.format("PASSED: %d!!", num))
end



local function every5()
	while idx <= maxidx do
		waitForPredicate(function() return (idx % 5) == 0 end)
		print("!! matched 5 !!")
		yield();
	end
end

local function test_whenever()
	local t1 = whenever(
		function() 
			if idx >maxidx then return nil end; 
			return (idx % 2) == 0 end,
		function() print("== EVERY 2 ==") end)
end

local function main()
	local t1 = spawn(counter, "counter", maxidx)

	local t6 = spawn(test_whenever);

	local t2 = spawn(predCount, 12)
	local t3 = spawn(every5)
	local t4 = spawn(predCount, 50)
	local t5 = when(
		function() return idx == 75 end, 
		function() print("WHEN IDX == 75!!") end)
	local t6 = when(function() return idx >= maxidx end,
		function() halt(); end);


end

run(main)



It’s a test case, so it’s doing some contrived things.  Basically, there is one task that is running a counter that throws a signal for every new number (up to maxid).  Then you can see the various tests which use predicates.

local function every5()
	while idx <= maxidx do
		waitForPredicate(function() return (idx % 5) == 0 end)
		print("!! matched 5 !!")
		yield();
	end
end

Here, we’re just running a continuous loop which will print it’s message every time the predicate is true. It seems kind of wasteful doesn’t it? Under normal circumstances, this would be a very hot spin loop, but when you call ‘waitForPredicate’, you task will alctually be thrown into a ‘suspended’ state, which means if there are other tasks to execute, they’ll go ahead, and you’ll get back in the queue to be tested later. So, it’s really, “test this predicate, if it’s not true, then throw the task at the back of the ready list, and test it again later. If it’s true, then continue on with whatever is next in this task”. The ‘yield()’ here is redundant.

In this particular case, we’ve essentially created a ‘whenever’ construct. This construct happens enough that it’s worth creating a convenience function for it.

local function test_whenever()
	local t1 = whenever(
		function() 
			if idx >maxidx then return nil end; 
			return (idx % 2) == 0 end,
		function() print("== EVERY 2 ==") end)
end

In this particular case, we let the ‘whenever’ construct do the work for us. Every other count, we’ll print our message. Of course, I’m using in place functions (lambda expressions?) in these test cases. They don’t have to be that way, you can set the functions however you want.

t6 is interesting because it says, ‘when the count reaches maxidx, halt the program’, which will in fact break us out of the main even loop and stop the program. Very convenient. This construct is useful because there may be myriad reasons why you’d want to stop the program. You can simply setup a predicate to do that. It could be a ‘when’ or perhaps you’d rather it be based on a signal, in that case use a signalOnPredicate/waitForSignal sort of thing. It’s composable, so use whatever set of constructs makes the most sense. It’s kind of a sane form of exception handling.

So there you have it, yet another construct tackled. Predicates are a simple construct that kind of extend the if/then flow control into the async realm. ‘when’ is almost a direct replacement for ‘if’ in this context. The waitOnPredicate is kind of a new construct I think. It’s like an if/spinlock, except you’re not spinning, you’re suspended with periodic checks on the predicate. And then of course the ‘signalOnPredicate’ is like a hail Mary pass. You don’t know who/what is going to respond, but you’re going to send up the signal. That’s like programming with interrupts, except, unless the scheduler allows for high priority interrupts/signals, these will be handled in the normal flow of cooperative processing.

Predicates are great, they’re a slightly different construct than I’ve typically used in my every day programming. They make some tasks a lot easier, and they make thinking about async programming more manageable.

And then there’s time…

Time is a lot easier construct to think about, because it’s well represented in most language frameworks already. Here are the time primitives:
 

  • waitUntilTime
  • sleep
  • delay
  • periodic

 
‘waitUntilTime’ is the lynch pin in this case. It will suspend the current task until the specified time. Time, in this case is a relative thing. The alarm module keeps its own clock, so everything is expressed relative to that clock.

sleep(seconds), will simply suspend the current task for a specified number of seconds. You can specify fractions of seconds, and the clock has nanosecond precision, but we’re not using a realtime scheduler, so you’ll get some amount of delay. Of course you could simply swap in a new scheduler and deal with any realtime requirements you might have.

delay, will spawn a task which will then execute the specified function after the specified amount of time has passed. This is kind of like a ‘when’ predicate, with a specialization for time. You could in fact reconstruct this primitive using the when predicate, but the alarm, knowing about time as it does, will do it more efficiently.

local Kernel = require("kernel"){exportglobal = true};
local Alarm = require("alarm")(Kernel)
local Clock = require("clock")

local c1 = Clock();

local function twoSeconds()
	print("TWO SECONDS: ", c1:secondsElapsed());
	Kernel:halt();
end

local function test_alarm_delay()
	print("delay(twoSeconds, 2000");
	Alarm:delay(twoSeconds, 2000);
end

run(test_alarm_delay)

periodic is similar, in that it well execute a function, but whereas ‘delay’ is a oneshot event, ‘periodic’ will repeat. In this way it is like the ‘whenever’ construct.

And there you have it. Between the predicates and the alarms, you have some new basic constructs for doing async programming. They are supported by the signaling construct that’s already a part of the kernel. They are simple add-ons, which means you can easily create your own constructs and replace these, or create completely new constructs which are similar. They can leverage the signaling mechanism, or maybe they want to do something else altogether.

So far, the constructs have been of the if/then variety, only in async fashion. I think there’s another set of constructs, which have to do with barriers and completions of tasks. That will clean up the other part of async, which is the ‘await’. We’ll see. In the meanwhile, next time, async io, which is pretty exciting.


TINN Version 0.7 Available

Although TINN is under constant development, there’s nothing like declaring a new “release”. It’s been 3 months since the 0.6 release. So, now there is a 0.7 release. You can read about the TINN v0.7 Release and install it if you would like.

There were 84 commits since the previous release, so I can’t even remember all the changes that were involved. The major addition from my most recent work has to do with the new scheduler as described on this blog. That’s the extensible, plug-in driven scheduler. Pretty nifty for my work at least.

There are quite a few additions, such as a revamped stream object, io completion port supported file interface, a logfile thing, and quite a few more interfaces from the OS.

Other items I have been working on include support for various COM interfaces such as DXGI, DXVA, MMDevice and some others. There are all in the “experimental” folder if you look at the enlistment. They are not quite ready for prime time, so they’re not actually in the v0.7 release.

What can you do with TINN? In short, you can create all sorts of Windows based applications. Everything from scalable web services to interactive multi-tasking UI (including OpenGL based).

TINN is a command line tool (tinn.exe). As such, the easiest thing to do is bring up a command line shell and run various scripts through tinn.

c:\> tinn.exe hello.lua

The TINN repository contains numerous test cases that utilize the various modules of TINN.

That’s it for now.  Next release will be about cleanup and stabilization primarily.


Computicles – A tale of two schedulers

One of the drivers for the creation of computicles is to maximize the efficiency of the running system while minimizing the complexity for the programmer.  Herein lies the rub.  Modern computers are multi-core/multi-proc, and Lua is largely a single core sort of system.  Lua has its own notion of “light weight threads”, which are essentially cooperative processing threads.  The native OS (Windows or Linux) has a notion of “threads” which are much more heavy weight.  While the Lua threads can number easily in the thousands and more, they are not actually running a parallel, they are just rapidly context switching between each other at the whim of the programmer.  The OS threads, on the other hand, are in fact running in parallel, on multiple cores if they exist.  But, as soon as you have more threads than you have cores, the threads are shifting rapidly between each other, just like in the Lua case, but it’s ‘preemptive’ instead of cooperative.

What I want?  I want to get the best of both worlds.  But, before starting down the path of leveraging the multiple cores, I want to start with the programming paradigm.

I want to write essentially serial code.  My brain is not good at dealing things like mutexes, semaphores, barriers, or any other kind of sharing mechanisms that have been invented over the past 40 years.  I know how to write straight sequential code.  I can deal with saying “spawn” to get something running in parallel, but that’s about it.

So, in steps computicles.

I’ve gone on about the subject a few times now, but I’ve finally created the unified scheduler that I require.  It looks like this:

 

-- comp_msgpump.lua
local ffi = require("ffi");
require("IOProcessor");

-- default to 15 millisecond timeout
gIdleTimeout = gIdleTimeout or 15

local idlecount = 0;

while true do
  if IOProcessor then
    IOProcessor:step();
  end

  local msg, err = SELFICLE:getMessage(gIdleTimeout);

  if not msg then
    if err == WAIT_TIMEOUT then
      --print("about to idle")
      idlecount = idlecount + 1;
      if OnIdle then
        OnIdle(idlecount);
      end
    end
  else
    local msgFullyHandled = false;
    msg = ffi.cast("ComputicleMsg *", msg);

    if OnMessage then
      msgFullyHandled = OnMessage(msg);
    end

    if not msgFullyHandled then
      msg = ffi.cast("ComputicleMsg *", msg);
      local Message = msg.Message;
      --print("Message: ", Message, msg.Param1, msg.Param2);
		
      if Message == Computicle.Messages.QUIT then
        if OnExit then
          OnExit();
        end
        break;
      end

      if Message == Computicle.Messages.CODE then
        local len = msg.Param2;
        local codePtr = ffi.cast("const char *", msg.Param1);
		
        if codePtr ~= nil and len > 0 then
          local code = ffi.string(codePtr, len);

          SELFICLE:freeData(ffi.cast("void *",codePtr));

          local func = loadstring(code);
          func();
        end
      end
      SELFICLE:freeMessage(msg);
    end
  end
end

 
This is pretty much the same event driven loop that has existed previously. It’s main function is to get messages off its message queue, and deal with them. This is how you communicate with a computicle. Under normal circumstances, a Computicle can simply implement either OnMessage(), if it wants to only respond when it receives a message. This is a perfectly event driven way to exist. Or it can implement OnIdle() if it wants to respond to the fact that nothing else is occuring in the system. This is a great combination, and will cover many useful cases. But what about waiting for some IO to complete?

Well, at the top of this event loop there is the IOProcessor:step() call. And what is an IOProcessor?

The IOProcessor is a scheduler for cooperative Lua threads. The IOProcessor assumes the user’s code is utilizing co-routines, and will deal with putting them on a ‘sleeping’ list whenever they perform a task, such as socket IO which does not complete immediately. It’s a classic, and before the Computicles existed, this was the primary scheduler.

It’s a bit thick with code, but here it is:

local ffi = require("ffi");

local Collections = require "Collections"
local IOCPSocket = require("IOCPSocket");
local SimpleFiber = require("SimpleFiber");
local IOCompletionPort = require("IOCompletionPort");
local SocketOps = require("SocketOps");


IOProcessor = {
  fibers = Collections.Queue.new();
  coroutines = {};
  EventFibers = {};
  FibersAwaitingEvent = {};

  IOEventQueue = IOCompletionPort:create();
  MessageQuanta = 15;		-- 15 milliseconds
};


--[[
	Socket Management
--]]

IOProcessor.createClientSocket = function(self, hostname, port)
  return IOCPSocket:createClient(hostname, port, self)
end

IOProcessor.createServerSocket = function(self, params)
  return IOCPSocket:createServerSocket(params, self)
end

IOProcessor.observeSocketIO = function(self, socket)
  return self.IOEventQueue:addIoHandle(socket:getNativeHandle(), socket.SafeHandle);
end

--[[
	Fiber Handling
--]]

IOProcessor.scheduleFiber = function(self, afiber, ...)
  if not afiber then
    return nil
  end
  self.coroutines[afiber.routine] = afiber;
  self.fibers:Enqueue(afiber);	

  return afiber;
end

IOProcessor.spawn = function(self, aroutine, ...)
  return self:scheduleFiber(SimpleFiber(aroutine, ...));
end

IOProcessor.removeFiber = function(self, fiber)
  self.coroutines[fiber.routine] = nil;
end

IOProcessor.inMainFiber = function(self)
  return coroutine.running() == nil; 
end

IOProcessor.yield = function(self)
  coroutine.yield();
end

IOProcessor.yieldForIo = function(self, sock, iotype)
  -- associate a fiber with a socket
  print("yieldForIo, CurrentFiber: ", self.CurrentFiber);
	
  self.EventFibers[sock:getNativeSocket()] = self.CurrentFiber;

  -- Keep a list of fibers that are awaiting io
  if self.CurrentFiber ~= nil then
    self.FibersAwaitingEvent[self.CurrentFiber] = true;

    -- Whether we were successful or not in adding the socket
    -- to the pool, perform a yield() so the world can move on.
    self:yield();
  end
end


IOProcessor.processIOEvent = function(self, key, numbytes, overlapped)
    local ovl = ffi.cast("SocketOverlapped *", overlapped);
    local sock = ovl.sock;
    ovl.bytestransferred = numbytes;
    if sock == INVALID_SOCKET then
		return false, "invalid socket"
    end

    --print("IOProcessor.processIOEvent(): ", sock, ovl.operation);

    local fiber = self.EventFibers[sock];
    if fiber then
      self:scheduleFiber(fiber);
      self.EventFibers[sock] = nil;
      self.FibersAwaitingEvent[fiber] = nil;
    else
      print("EventScheduler_t.ProcessEventQueue(), No Fiber waiting to process.")
      -- remove the socket from the watch list
    end
end

IOProcessor.stepIOEvents = function(self)
    -- Check to see if there are any IO Events to deal with
    local key, numbytes, overlapped = self.IOEventQueue:dequeue(self.MessageQuanta);

    if key then
      self:processIOEvent(key, numbytes, overlapped);
    else
      -- typically timeout
      --print("Event Pool ERROR: ", numbytes);
    end
end

IOProcessor.stepFibers = function(self)
  -- Now check the regular fibers
  local fiber = self.fibers:Dequeue()

  -- Take care of spawning a fiber first
  if fiber then
    if fiber.status ~= "dead" then
      self.CurrentFiber = fiber;
      local result, values = fiber:Resume();
      if not result then
        print("RESUME RESULT: ", result, values)
      end
      self.CurrentFiber = nil;

      if fiber.status ~= "dead" and not self.FibersAwaitingEvent[fiber] then
        self:scheduleFiber(fiber)
      else
        --print("FIBER FINISHED")
        -- remove coroutine from dictionary
        self:removeFiber(fiber)
      end
    else
      self:removeFiber(fiber)
    end
  end
end

IOProcessor.step = function(self)
  self:stepFibers();
  self:stepIOEvents();
end

return IOProcessor

There are a couple of ways to approach this. From the perspective of the other event loop, the “step()” method here is executed once around the loop. The ‘step()’ method in turn checks on the fibers, and then on the ioevents. “stepFibers” checks the list of fibers that are ready to run, and runs one of them for a bit until it yields, and is thus placed back on the queue of fibers ready to be run, or it finishes. This is the part where a normal cooperative processing system could be brought to its knees, and a preemptive multi-tasking system would just keep going. The ‘stepIOEvents()’ function checks on the IOCompletionPort that is being used by sockets to indicate whether anything interesting has occured. If there has been any activity, the cooperative thread associated with the activity is scheduled to execute a bit of code. It does not execute immediately, but it is now on the list to be executed next time around.

The stepIOEvents() function is at the heart of any system, such as node.js, which gets high performance with IO processing, while maintaining a low CPU load. Most of the time you’re just waiting, doing nothing, and once the system indicates there is action on the socket, you can spring into action. Thus, you do not spend any time looping over sockets polling to see if there’s any activity, you’re just notified when there is.

The rest of the code is largely helpers, like creating a socket that is wired correctly and whatnot.

So, at the end of it, what does this system do?

Well, assuming I want to write a DateTimeClient, which talks to a service, gets the date and time, prints it out, etc, I would write this:

local ffi = require "ffi"
require("IOProcessor");

local daytimeport = 13

GetDateAndTime = function(hostname, port)
    hostname = hostname or "localhost";
    port = port or daytimeport;

    local socket, err = IOProcessor:createClientSocket(hostname, port);

    if not socket then
        print("Socket Creation Failed: ", err);
        return nil, err;
    end

    local bufflen = 256;
    local buff = ffi.new("char [?]", bufflen);

    local n, err = socket:receive(buff, bufflen)
 
    if not n then
        return false, err;
    end

    if n > 0 then
        return ffi.string(buff, n);
    end
end

Well, that looks like normal sequential code to me. And yes, it is. Nothing unusual. But, when running in the context of a computicle, like the following, it gets more interesting.

local Computicle = require("Computicle");

local codeTemplate = [[
require("DaytimeClient");
local dtc, err = GetDateAndTime("localhost");
print(dtc);
]]

local comp1 = Computicle:create(codeTemplate);
local comp2 = Computicle:create(codeTemplate);

comp1:waitForFinish();
comp2:waitForFinish();

This will take the otherwise sequential code of the DateTimeClient, and execute it in two parallel preemptive Operating System level threads, and wait for their completion. The magic is all hidden behind the schedulers and event loops. I never have to know about how that all happens, but I can appreciate the benefits.

Marrying the concepts of event driven, muti-process, cooperative user space threads, preemptive multi-tasking, and the like can be a daunting task. But, with a little bit of script, some chewing gum, a whistle and a prayer, it all comes together in a seamless whole which is quite easy to use, and fairly simple to understand. I think I have achieved my objectives for ease of use, maximizing efficiency, and reducing head explosions.


Computicles – Unsafe, but fun, code injection

Computicles are capable of receiving bits of code to execute. That is in fact one way in which they communicate with each. From .
one context I can simple do: comp.someValue = 100, and that will set “someValue = 100” in another context. Well, great. How about sending something across that’s more substantial than a simple variable setting?

Well, with the Computicle.exec() method, which the previous example is based on, you can really send across any bit of code to be executed. It works, and you can even send across the body of a function like this:

comp:exec[[
function hello()
  print("Hello, World!");
end
]]

That works fine, and you have full access to all stuff that’s running in that context. It’s a bit clunky though because the entirety of your piece of code is wrapped up in a string value. This is very similar to executing SQL code on some server. The bulk of your code, if not in stored procedures”, ends up in these opaque strings. Hard to catch errors, hard to debug, etc. How about the following:

comp.hello = function()
  print("Hello, World!");
end

What that you say? Basically, assigning a function as a variable to the computicle. Yes, this can work. There is a slight modification to turn a function into a string, and it looks like this:

Computicle.datumToString = function(self, data, name)
	local dtype = type(data);
	local datastr = tostring(nil);

--print("DATUM TYPE: ", name, dtype);

	if type(data) == "cdata" then
		-- If it is a cdata type that easily converts to 
		-- a number, then convert to a number and assign to string
		if tonumber(data) then
			datastr = tostring(tonumber(data));
		else
			-- if not easily converted to number, then just assign the pointer
			datastr = string.format("TINNThread:StringToPointer(%s);", 
				TINNThread:PointerToString(data));
		end
	elseif dtype == "table" then
		if getmetatable(data) == Computicle_mt then
			-- package up a computicle
		else
			-- get a json string representation of the table
			datastr = string.format("[[ %s ]]",JSON.encode(data, {indent=true}));

			--print("=== JSON ===");
			--print(datastr)
		end
	elseif dtype == "function" then
		datastr = "loadstring([["..string.dump(data).."]])";
	elseif dtype == "string" then
		datastr = string.format("[[%s]]", data);
	else 
		datastr = tostring(data);
	end

	return datastr;
end

Notice the part that starts: ‘elseif dtype == “function()” then’.

Basically, there is a string function that turns anything into bytecode which can later be hydrated using loadstring later. It is placed in ‘loadstring([[…]])’, because this is the only way to preserve the actual 8-bit values. If you use string.format(“%s”), it will chop out the non-ascii stuff.

Then, this code can be executed in the remote context just the same as any other little bit of code. There are some restrictions to what kinds of functions you can do this with though. No ‘upvalues’, meaning, everything must be contained within the function itself, no calling out to global variables and the like.

Of course, that just gets the code over to the other side in a convenient way. What about actually executing the code?

comp:exec([[hello()]]);

Same as ever, just make the function call using “exec()”. Of course, this little bit could be wrapped up in some other convenient override, like using the ‘:’ notation, but there’s some more work to be done before making that a reality.

What other functions can be dealt with? Well, the loop running within the computicle looks like the following now:

-- comp_msgpump.lua

local ffi = require("ffi");

-- This is a basic message pump
-- 

-- default to 15 millisecond timeout
gIdleTimeout = gIdleTimeout or 15


local idlecount = 0;

while true do
  local msg, err = SELFICLE:getMessage(gIdleTimeout);
  -- false, WAIT_TIMEOUT == timed out
  --print("MSG: ", msg, err);

  if not msg then
    if err == WAIT_TIMEOUT then
      --print("about to idle")
      idlecount = idlecount + 1;
      if OnIdle then
        OnIdle(idlecount);
      end
    end
  else
  	local msgFullyHandled = false;

    if OnMessage then
      msgFullyHandled = OnMessage(msg);
    end

    if not msgFullyHandled then
      msg = ffi.cast("ComputicleMsg *", msg);
      local Message = msg.Message;
      --print("Message: ", Message, msg.Param1, msg.Param2);
		
      if Message == Computicle.Messages.QUIT then
        break;
      end

      if Message == Computicle.Messages.CODE then
        local len = msg.Param2;
        local codePtr = ffi.cast("const char *", msg.Param1);
		
        if codePtr ~= nil and len > 0 then
          local code = ffi.string(codePtr, len);

          SELFICLE:freeData(ffi.cast("void *",codePtr));

          local func = loadstring(code);
          func();
        end
      end
      SELFICLE:freeMessage(msg);
    end
  end
end

This new message pump has a couple of interesting new features. The first feature has to do with the getMessage(). It will timeout after some number of milliseconds have passed and a message hasn’t come in. If there is an ‘OnIdle()’ function defined, it will be called, passing that function the current count. If that function does not exist, then nothing will happen.

The second change has to do with message processing. If there is a “OnMessage()” function defined, it will be called, and the message will be handed to it for processing. If that function does not exist, then it will perform some default actions, such as reading and code, and possibly handling a “QUIT”.

So, how about that OnIdle? that’s a function that takes a parameter. Can I inject that? Sure can:

comp.OnIdle = function(count)
  print("IDLE", count)
end

Just the the hello() case, except this one can take a parameter. This does not violate the “no upvalues” rule, so it’s just fine.

In this case, I don’t have to actually execute the code, because the loop within the computicle will pick up on it and execute it. And if you wanted to remove this idling funcition, simple do: ‘comp.OnIdle = nil’

And then what?

Well, that’s pretty cool. Now I can easily set simple variables, and I can set table values, and I can even set functions to be called. I have a generic message pumping loop, which has embedded “OnIdle”, and “OnMessage” functions.

The last little bit of work to be done here is to deal with Asynchronous IO in a relatively seamless way using continuations, just like I had in the pre-computicle world. That’s basically a marriage of the core of the EventScheduler and the main even loop here.

Throw some authentication on top of it all and suddenly you have a system that is very cool, secure, and useful.


Computicles – Inter-computicle communication

Alrighty then, so a computicle is a vessel that holds a bit of computation power. You can communicate with it, and it can communicate with others.

Most computicles do not stand as islands unto themselves, so easily communicating with them becomes very important.

Here is some code that I want to be able to run:

local Computicle = require("Computicle");
local comp = Computicle:load("comp_receivecode");

-- start by saying hello
comp:exec([[print("hello, injector")]]);

-- queue up a quit message
comp:quit();

-- wait for it all to actually go through
comp:waitForFinish();

So, what’s going on here? The first line is a standard “require” to pull in the computicle module.

Next, I create a single instance of a Computicle, running the Lua code that can be found in the file “comp_receivecode.lua”. I’ll come back to that bit of code later. Suffice to say it’s running a simple computicle that does stuff, like execute bits of code that I hand to it.

Further on, I use the Computicle I just created, and call the “exec()” function. I’m passing a string along as the only parameter. What will happen is the receiving Computicle will take that string, and execute the script from within its own context. That’s actually a pretty nifty trick I think. Just imagine, outside the world of scripting, you can create a thread in one line of code, and then inject a bit of code for that thread to execute. Hmmm, the possibilities are intriguing methinks.

The tail end of this code just posts a quit, and then finally waits for everything to finish up. Just not that the ‘quit()’ function is not the same thing as “TerminateThread()”, or “ExitThread()”. Nope, all it does is post a specific kind of message to the receiving Computicle’s queue. What the thread does with that QUIT message is up to the individual Computicle.

Let’s have a look at the code for this computicle:

local ffi = require("ffi");

-- This is a basic message pump
-- 
while true do
  local msg = SELFICLE:getMessage();
  msg = ffi.cast("ComputicleMsg *", msg);
  local Message = msg.Message;

  if OnMessage then
    OnMessage(msg);
  else
    if Message == Computicle.Messages.QUIT then
      break;
    end

    if Message == Computicle.Messages.CODE then
      local len = msg.Param2;
      local codePtr = ffi.cast("const char *", msg.Param1);
		
      if codePtr ~= nil and len > 0 then
        local code = ffi.string(codePtr, len);

        SELFICLE:freeData(ffi.cast("void *",codePtr));

        local f = loadstring(code);
	f();
      end
    end
  end

  SELFICLE:freeMessage(msg);
end

It’s not too many lines. This little Computicle takes care a few scenarios.

First of all, if there so happens to be a ‘OnMessage’ function defined, it will receive the message, and the main loop will do no further processing of it.

If there is no ‘OnMessage’ function, then the message pump will handle a couple of cases. In case a ‘QUIT’ message is received, the loop will break and the thread/Computible will simply exit.

When the message == ‘CODE’ things get really interesting. The ‘Param1’ of the message contains a pointer to the actual bit of code that is intended to be executed. The ‘Param2’ contains the length of the specified code.

Through a couple of type casts, and an ffi.string() call, the code is turned into something that can be used with ‘loadstring()’, which is a standard Lua function. It will parse the string, and then when ‘f()’ is called, that string will actually be executed (within the context of the Computicle). And that’s that!

At the end, the ‘SELFICLE:freeMessage()’ is called to free up the memory used to allocate the outer message. Notice that ‘SELFICLE:freeData()’ was used to clean up the string value that was within the message itself. I have intimate knowledge of how this message was constructed, so I know this is the correct behavior. In general, if you’re going to pass data to a computicle, and you intend the Computicle to clean it up, you should use the computicle instance “allocData()” function.

OK. So, that explains how I could possibly inject some code into a Computicle for execution. That’s pretty nifty, but it looks a bit clunky. Can I do better?

I would like to be able to do the following.

comp.lowValue = 100;
comp.highValue = 200;

In this case, it looks like I’m setting a value on the computicle instance, but in which thread context? Well, what will actually happen is this will get executed within the computicle instance context, and be available to any code that is within the computicle.

We already know that the ‘exec()’ function will execute a bit of code within the context of the running computicle, so the following should now be possible:

comp:exec([[print(" Low: ", lowValue)]]);
comp:exec([[print("High: ", highValue)]])

Basically, just print those values from the context of the computile. If they were in fact set, then this should print them out. If there were not in fact set, then it should print ‘nil’ for each of them. On my machine, I get the correct values, so that’s an indication that they were in fact set correctly.

How is this bit of magic achieved?

The key is the Lua ‘__newindex’ metamethod. Wha? Basically, if you have a table, and you try to set a value that does not exist, like I did with ‘lowValue’ and ‘highValue’, the ‘__newindex()’ function will be called on your table if you’ve got it setup right. Here’s the associated code of the Computicle that does exactly this.

__newindex = function(self, key, value)
  local setvalue = string.format("%s = %s", key, self:datumToString(value, key));
  return self:exec(setvalue);
end

That’s pretty straight forward. Just create some string that represents setting whatever value you’re trying to set, and then call ‘exec()’, which is already known to execute within the context of the thread. So, in the case where I have written “comp.lowValue = 100”, this will turn into a sting that == “lowValue == 100”, and that string will be executed, setting a global variable ‘lowValue’ == 100.

And what is this ‘datumToString()’ function? Ah yes, this is the little bit that takes various values and returns their string equivalent, ready to be injected into a running Computicle.

Computicle.datumToString = function(self, data, name)
  local dtype = type(data);
  local datastr = tostring(nil);

  if type(data) == "cdata" then
      -- If it is a cdata type that easily converts to 
      -- a number, then convert to a number and assign to string
    if tonumber(data) then
      datastr = tostring(tonumber(data));
    else
      -- if not easily converted to number, then just assign the pointer
      datastr = string.format("TINNThread:StringToPointer(%s);", 
        TINNThread:PointerToString(data));
    end
  elseif dtype == "table" then
    if getmetatable(data) == Computicle_mt then
      -- package up a computicle
    else
      -- get a json string representation of the table
      datastr = string.format("[[ %s ]]",JSON.encode(data, {indent=true}));
    end
  elseif dtype == "string" then
    datastr = string.format("[[%s]]", data);
  else 
    datastr = tostring(data);
  end

  return datastr;
end

The task is actually fairly straight forward. Given a Lua based value, turn it into a string that can be executed in another Lua state. There are of course methods in Lua which will do this, and tons of marshalling frameworks as well. But, this is a quick and dirty version that does exactly what I need.

Of particular note are the handling of cdata and table types. For cdata, some of the values, such as ‘int64_t’, I want to just convert to a number. Tables are the most interesting. This particular technique will really only work for fairly simple tables, that do not make references to other tables and the like. Basically, turn the table into a JSON string, and send that across to be rehydrated as a table.

Here’s some code that actually makes use of this.

comp.contacts = {
  {first = "William", last = "Adams", phone = "(111) 555-1212"},
  {first = "Bill", last = "Gates", phone = "(111) 123-4567"},
}

comp:exec([=[
print("== CONTACTS ==")

-- turn contacts back into a Lua table
local JSON = require("dkjson");

local contable = JSON.decode(contacts);


for _, person in ipairs(contable) do
	--print(person);
	print("== PERSON ==");
	for k,v in pairs(person) do
		print(k,v);
	end
end
]=]);

Notice that ‘comp.contacts = …’ just assigns the created table directly. This is fine, as there are no other references to the table on ‘this’ side of the computicle, so it will be safely garbage collected after some time.

The rest of the code is using the ‘exec()’, so it is executing in the context of the computicle. It basically gets the value of the ‘contacts’ variable, and turns it back into a Lua table value, and does some regular processing on it (print out all the values).

And that’s about it. From the humble beginnings of being able to inject a bit of code to run in the context of an already running thread, to exchanging tables between two different threads with ease, Computicles make pretty short work of such a task. It all stems from the same three principles of Computicles: listen, compute, communicate. And again, not a single mutex, lock, or other visible form of synchronization. The IOCompletionPort is the single communications mechanism, and all the magic of serialized multi-threaded communication hide behind that.

Of course, ‘code injection’ is a dirty word around the computing world, so there must be a way to secure such transfers? Yah, sure, why not. I’ve been bumping around the indentity/security/authorization/authentication space recently, so surely something must be applicable here…