The plugin host process embeds python, and calls into the plugin's python class to create the plugin instance. It then, when IndigoServer (or Cocoa client) initiates actions (ex: plugin menu item being selected, a plugin defined action needs to be executed, etc.), calls out to the python plugin instance defined callback methods. Example callbacks might change a plugin preference, send a command to a serial queue, generate a report, change the state of a device, etc.
One such optional callback function is runConcurrently(). If the plugin defines that, then the host automatically creates a new thread and calls that function after the plugin is created. The plugin never returns from that function (unless the host tells it to shutdown), so from there the plugin can:
- Loop doing periodic processing with a sleep call (NOAA plugin, iTunes sync plugin, etc.)
- Use asynccore to handle network and serial I/O
- Use Twisted to handle all events (call reactor.run())
The other python callback functions (say, for an IndigoServer triggered action) can communicate with the main runConcurrently() thread however they want, via a queue, asyncore or Twisted. Twisted isn't thread safe, so inside python callbacks you have to defer the function call, but twisted makes that easy with the reactor.callFromThread() function.
So I think to answer your question: the plugin is responsible for its own event loop but there are callbacks into the plugin as well. And it is one persistent process (we call it the Indigo Host client) per plugin. The Indigo Host is the master of the python plugin instance, but will let the plugin pretty much run on its own if needed via the runConcurrently() function. IndigoServer will manage launching all of these host processes and stopping them if the plugin is disabled.
Everyone please note these are technical details, and we'll be providing lots of documentation and examples. It will be much easier to use than the above might sound.