Add a backlog of posts that I just forgot to commit
This commit is contained in:
parent
7c9354457b
commit
30ab44c4c4
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
layout: post
|
||||
title: "FOSDEM: Testing and Automation Dev Room CFP"
|
||||
tags:
|
||||
- fosdem
|
||||
- fosdem2013
|
||||
---
|
||||
|
||||
For this next year's FOSDEM, I'm organizing the "Testing and Automation"
|
||||
developer room. And wouldn't you know it, we've just opened up our [Call for
|
||||
Participation](https://gist.github.com/4107243).
|
||||
|
||||
I'm quite excited about the dev room, and look forward to reviewing and
|
||||
selecting the talks.
|
||||
|
||||
Hope to see you there :)
|
||||
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
layout: post
|
||||
title: Tyler goes to Yurp
|
||||
tags:
|
||||
- fosdem
|
||||
- fosdem2013
|
||||
- roadtrip
|
||||
- europe
|
||||
---
|
||||
|
||||
As I mentioned in my [previous
|
||||
post](/2012/11/18/testing-automation-devroom-fosdem.html) I'll be going to
|
||||
[FOSDEM](http://fosdem.org) this year. Unlike last year, I will be spending a
|
||||
*lot* more time in Europe this time around.
|
||||
|
||||
I will be arriving in Frankfurt on the 29th of January and spending a few days
|
||||
in Köln (Cologne). Naturally I will be in Brussels for FOSDEM for a couple
|
||||
days, but after that, I will be heading to
|
||||
[Berlin](https://en.wikipedia.org/wiki/Berlin) for a few weeks.
|
||||
|
||||
I've already spent a good amount of time in Germany, so I won't be on the
|
||||
"tourist track", having seen most of the sights in Berlin already.
|
||||
|
||||
So I will be working from Berlin, and my weekends and evenings will be open to
|
||||
as many meetups/hackathons as I can find. Even if you don't want to hang out
|
||||
(it's okay, I understand), but know of some good events in Berlin that are
|
||||
worth checking out, please send me an email (tyler@linux.com) and let me know!
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
*What the hell is Yurp?*
|
||||
|
||||
Having spent a large amount of my time in the southern US, "Yurp" is how *far*
|
||||
too many southern people pronounce "Europe", including those in my own family.
|
||||
That's why I'm going to Yurp.
|
|
@ -0,0 +1,227 @@
|
|||
---
|
||||
layout: post
|
||||
title: Safe, Dynamic Task Creation in Ada
|
||||
tags:
|
||||
- ada
|
||||
- programming
|
||||
---
|
||||
|
||||
|
||||
A few years ago,
|
||||
[Ada](https://secure.wikimedia.org/wikipedia/en/wiki/Ada_(programming_language)
|
||||
become my hobby/tinker programming language of choice, for a [number of
|
||||
reasons](/2010/12/06/ada-surely-you-jest-mr-pythonman.html), concurrency being
|
||||
one of them. In this post I'd like to walk you through an example of dynamic
|
||||
task creation in Ada, which uses `Ada.Task_Termination` handlers, a new feature
|
||||
in Ada 2005.
|
||||
|
||||
(If you're familiar with Ada, you can skip this next section)
|
||||
|
||||
---
|
||||
|
||||
> *Note:* You can find all this code, and more in my
|
||||
[ada-playground](https://github.com/rtyler/ada-playground) repository on GitHub
|
||||
|
||||
---
|
||||
|
||||
Similar to C, Ada supports stack allocated variables as well as heap allocated
|
||||
variabels, it also defaults to stack allocation. For example:
|
||||
|
||||
{% highlight ada %}
|
||||
|
||||
procedure Main is
|
||||
-- A stack allocated `Integer` object
|
||||
Enough_Memory : constant Integer := 655360;
|
||||
begin
|
||||
null;
|
||||
end Main;
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
If you wanted to allocate that `Integer` onto the heap, then you would use the
|
||||
`new` keyword:
|
||||
|
||||
{% highlight ada %}
|
||||
|
||||
procedure Main is
|
||||
-- A heap allocated `Integer` pointer
|
||||
Enough_Memory : access Integer := new Integer'(655360);
|
||||
begin
|
||||
null;
|
||||
end Main;
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
|
||||
I won't dive too much into the minutia of what is going on here, if you're not
|
||||
familiar with Ada already you can learn more about [access types on the Ada
|
||||
Programming
|
||||
Wikibook](http://en.wikibooks.org/wiki/Ada_Programming/Types/access). Basically
|
||||
we're heap allocating a new Integer and using an **access type** (aka: typed
|
||||
pointer) to keep track of it. Keen readers will notice we didn't do anything
|
||||
with that Integer access type, and we're _technically_ leaking the memory. To
|
||||
solve this we use the generic unit `Ada.Unchecked_Deallocation`, which gives
|
||||
you a facility for properly freeing memory ([more details
|
||||
here](http://en.wikibooks.org/wiki/Ada_Programming/Types/access#Deleting_objects_from_a_storage_pool)).
|
||||
|
||||
|
||||
---
|
||||
|
||||
### Tasking Trickiness
|
||||
|
||||
Concurrency is part of the language in Ada, and is handled through
|
||||
[tasking](http://en.wikibooks.org/wiki/Ada_Programming/Tasking). A basic
|
||||
example of might be:
|
||||
|
||||
{% highlight ada %}
|
||||
with Ada.Text_IO;
|
||||
|
||||
procedure Main is
|
||||
task Counter;
|
||||
|
||||
task body Counter is
|
||||
begin
|
||||
for Count in 1 .. 10 loop
|
||||
Ada.Text_IO.Put_Line (Count'Img);
|
||||
end loop;
|
||||
end Counter;
|
||||
begin
|
||||
null;
|
||||
end Main;
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
The way tasks in Ada work means that the `Counter` task will be created,
|
||||
started and then the execution of the `Main` program will block until the
|
||||
`Counter` task completes (important detail).
|
||||
|
||||
|
||||
The trickiness starts to arrive when you talk about dynamically allocating task
|
||||
objects, and combine that with something like an infinite loop, such as one
|
||||
might find in a server program, e.g.:
|
||||
|
||||
{% highlight ada %}
|
||||
|
||||
procedure Main is
|
||||
begin
|
||||
-- Socket set up omitted
|
||||
loop
|
||||
declare
|
||||
Client_Socket : Socket_Type;
|
||||
Request_Handler : Handler_Ptr := new Handler;
|
||||
begin
|
||||
-- Block until we receive a new inbound connection
|
||||
Accept_Socket (Server_Socket, Client_Socket, Server_Addr);
|
||||
-- Dereference the Handler_Ptr and call `Process` on the Handler
|
||||
-- task
|
||||
Request_Handler.all.Process (Client_Socket);
|
||||
end;
|
||||
end loop;
|
||||
end Main;
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
(The code above is an abbreviated version of `echomultitask_main.adb` which [can
|
||||
be found
|
||||
here](https://github.com/rtyler/ada-playground/blob/master/echomultitask_main.adb)).
|
||||
|
||||
The issue with this code is that we're allocating a new `Handler` task for
|
||||
every in-bound connection, and we have no means of ever cleaning them up
|
||||
properly. If we were to create an Array of `Handler_Ptr`, we still would have
|
||||
to find some mechanism (which exists) to check the status of each `Handler` to
|
||||
determine if we should clean it up. Problem being, we'd have to loop through
|
||||
all the active tasks, checking for a "terminated" status, in order to
|
||||
deallocate them. It'd be much better if a task could tell us when it's
|
||||
finished, rather than us polling every one.
|
||||
|
||||
Fortunately in Ada 2005, a mechanism was added to make it easier to add
|
||||
"clean-up" to tasks: **`Ada.Task_Termination`**. The package allows you to set
|
||||
up a termination handler for the a specific task, which the runtime will call
|
||||
when that task terminates. _Unfortunately_ however, the handler procedure that
|
||||
can be invoked when the task terminates will **not** be passed a pointer to
|
||||
the task itself, but rather the `Task_Id` (`Ada.Task_Identification.Task_Id`).
|
||||
|
||||
**So close** to being able to properly deallocate these dynamic tasks, but we
|
||||
need one more component, a protected object with a hash map inside of it:
|
||||
|
||||
{% highlight ada %}
|
||||
|
||||
package Server.Handlers is
|
||||
|
||||
protected Coordinator is
|
||||
procedure Track (Ptr : in Handler_Ptr);
|
||||
private
|
||||
Active_Tasks : Handler_Containers.Map;
|
||||
end Coordinator;
|
||||
|
||||
end Server.Handlers;
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
Then back in `main.adb`:
|
||||
|
||||
{% highlight ada %}
|
||||
|
||||
Accept_Socket (Server_Socket, Client_Socket, Server_Addr);
|
||||
Request_Handler.all.Process (Client_Socket);
|
||||
-- Make sure the we keep track of the Request_Handler in order to properly
|
||||
-- deallocate it later
|
||||
Server.Handlers.Coordinator.Track (Request_Handler);
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
(The code above is an abbreviated version of `echomultitask-worker.ads` which
|
||||
[can be found
|
||||
here](https://github.com/rtyler/ada-playground/blob/master/echomultitask-worker.ads))
|
||||
|
||||
The singleton protected object `Coordinator` not only will give us protected
|
||||
(aka thread safe) access to the `Active_Tasks` map, but also gives us a
|
||||
protected object to hang our `Ada.Task_Termination.Termination_Handler`
|
||||
protected procedure off of:
|
||||
|
||||
|
||||
{% highlight ada %}
|
||||
|
||||
protected body Server.Handlers is
|
||||
|
||||
protected body Coordinator is
|
||||
|
||||
procedure Last_Wish (C : Ada.Task_Termination.Cause_Of_Termination;
|
||||
T : Ada.Task_Identification.Task_Id;
|
||||
X : Ada.Exceptions.Exception_Occurrence) is
|
||||
begin
|
||||
-- Deallocate our task identified by `T`
|
||||
-- and make sure we remove it from `Active_Tasks`
|
||||
end Last_Wish;
|
||||
|
||||
procedure Track (Ptr : in Handler_Ptr) is
|
||||
-- Dereference our `Handler` task, and fish out its Task_Id
|
||||
Handler_Id : Ada.Task_Idenfitication.Task_Id := Ptr.all'Identity
|
||||
begin
|
||||
-- Add `Handler_Id` to our `Active_Tasks` map
|
||||
Active_Tasks.Insert (Handler_Id, Ptr);
|
||||
|
||||
-- Set up the Last_Wish procedure to be executed after our task has
|
||||
-- terminated
|
||||
Ada.Task_Termination.Set_Specific_Handler (Handler_Id, Last_Wish'Access);
|
||||
end Track;
|
||||
|
||||
end Coordinator;
|
||||
|
||||
end Server.Handlers;
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
(The code above is an abbreviated version of `echomultitask-worker.adb` which
|
||||
[can be found here](https://github.com/rtyler/ada-playground/blob/master/echomultitask-worker.adb))
|
||||
|
||||
|
||||
This approach will allow us to safely create new dynamic tasks to handle the
|
||||
incoming requests, but will also make sure that the tasks are cleanly
|
||||
deallocated when they terminate.
|
||||
|
||||
If you're interested in concurrency in Ada, I
|
||||
highly recommend purchasing [Concurrent and Real-Time Programming in
|
||||
Ada](http://www.amazon.com/gp/product/0521866979?ie=UTF8&tag=unethicalblog-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0521866979)
|
||||
by Alan Burns and Andy Wellings, it's been tremendously helpful for my own
|
||||
concurrency exploration in Ada.
|
Loading…
Reference in New Issue