= Threads =
jack_process:
 add new ports
 reads queued snd_seq_event's
 if PORT_EXIT: mark port as dead
 if PORT_ADD, PORT_CHANGE: send addr to a2j_port_thread (it also may mark port as dead)
 else process input event
 remove dead ports and send them to a2j_port_thread

 remove dead ports and send them to a2j_port_thread
 add new ports
 queue output events

main_loop:
 free deleted ports
 create new ports or mark existing as dead

= ringbuffers =

 * early_events ( alsa_midi_event_t + data)
 * new_ports
 * port_add (snd_seq_addr_t)
 * port_del (port_t *)

= port life cycle =
== port birth ==
 * during jack process function execution, in a2j_port_event(), event
   about port creation is received from system alsa seq client and
   port alsa seq address is written to port_add ringbuffer.
 * In main loop, a2j_update_ports() is called. a2j_update_ports()
   reads port alsa seq address from port_add ringbuffer. If port is
   new one and should be exported, it is created by calling
   a2j_port_create() in a2j_update_port_type() and port pointer is
   added to new_ports ringbuffer.
 * during jack process function execution, in a2j_add_ports(), port
   pointer is read from new_ports ringbuffer and port is added to port
   hash.

== port death ==
 * during jack process function execution, in a2j_port_event(), event
   about port destruction is received from system alsa seq client and
   port is marked as dead.
 * during jack process function execution, in
   a2j_jack_process_internal() ports marked as dead are removed from
   port hash and port address is written to port_del ringbuffer.
 * In main loop, a2j_free_ports() is called. It pops port pointers
   from port_del ringbuffer and frees ports.

= Call graph generation =
  CFLAGS='-dr' ./waf configure
  ./waf
  make cg
  file build/call_graph.*
