2
votes

No knowledge of USB needed for this question, just described it as it is to make the example more conrete.

I'm trying to implement a dynamic supervisor for specific devices on a USB bus. These devices have addresses and appear and disappear during the lifetime of the system.

For each device I need a dynamic child for my supervisor.

These children are transient, so once they crash or terminate we don't restart them (because probably they are gone then).

I have a process that scans the USB port at certain times and produces a list of all addresses of the USB devices I want to handle.

I plan to call supervisor:which_children/1 before each scan to find out which devices are present but have no child process running.

In order to find out which addresses have children running I plan to create Id atoms for the childspec that contain the addresses (there are only a few addresses possible), e.g. adr_12 if the child handles address 12.

When I try to start/restart missing children I have the somewhat ugly situation that the child specs are not automatically deleted when the transient child terminates or crashes (at least I think that it is so). So I would need code like this:

case supervisor:start_child(my_sup, Spec) of
    {error, already_present} ->
        supervisor:restart_child(my_sup, Spec);
    Any -> Any
end

Then there is the problem that I don't know if supervisor:which_children/1 also returns already terminated children.

So it would be best if children would be deleted after they transiently terminate.

Somehow all this feels inelegant to me so I'm asking myself (and you):

How can I resolve this most elegantly?

Is it better not to use a supervisor at all in this situation?

2

2 Answers

2
votes

My gut feeling/knee jerk reaction is: 'You need to use a simple_one_for_one' supervisor for them, so their spec gets removed when it stops. If you need to be able to grab a specific process for communication, I would use the gproc application for that (or an ETS table).

1
votes

It sounds to me like the children you want to dynamically add to your supervisor are very similar each other. Maybe a simple-one-for-one supervisor is what you need. These supervisors are "a simplified version of the one_for_one supervisor, where all child processes are dynamically added instances of the same process.". Every child will have the same child specs, so you don't need to specify it when you call the supervisor:add_child/2.

Also, mind that the above idea of creating an atom (e.g. adr_12) dynamically could be dangerous. Atoms are limited in an Erlang system (by default ~1000000). See the documentation for details.