Un selector permite manejar en un único hilo de ejecución la entrada salida
de file descriptors de forma no bloqueante.
Esconde la implementación final (select(2) / poll(2) / epoll(2) / ..)
El usuario registra para un file descriptor especificando:
1. un handler: provee funciones callback que manejarán los eventos de
entrada/salida
2. un interés: que especifica si interesa leer o escribir.
Es importante que los handlers no ejecute tareas bloqueantes ya que demorará
el procesamiento del resto de los descriptores.
Si el handler requiere bloquearse por alguna razón (por ejemplo realizar
una resolución de DNS utilizando getaddrinfo(3)), tiene la posiblidad de
descargar el trabajo en un hilo notificará al selector que el resultado del
trabajo está disponible y se le presentará a los handlers durante
la iteración normal. Los handlers no se tienen que preocupar por la
concurrencia.
Dicha señalización se realiza mediante señales, y es por eso que al
iniciar la librería `selector_init' se debe configurar una señal a utilizar.
Todos métodos retornan su estado (éxito / error) de forma uniforme.
Puede utilizar `selector_error' para obtener una representación human
del estado. Si el valor es `SELECTOR_IO' puede obtener información adicional
en errno(3).
El flujo de utilización de la librería es:
- iniciar la libreria `selector_init'
- crear un selector: `selector_new'
- registrar un file descriptor: `selector_register_fd'
- esperar algún evento: `selector_iteratate'
- destruir los recursos de la librería `selector_close'