Index: libroar/Makefile
===================================================================
--- libroar/Makefile	(revision 5619)
+++ libroar/Makefile	(revision 5692)
@@ -11,5 +11,5 @@
 PASSWORD=passwordapi.o pinentry.o sshaskpass.o
 CRYPTO=crypto.o random.o $(HASHES) crc.o
-OBJS=libroar.o config.o debug.o error.o basic.o stream.o client.o simple.o auth.o socket.o ctl.o buffer.o meta.o file.o acl.o cdrom.o $(PASSWORD) $(VIO) stack.o slp.o nnode.o roardl.o plugincontainer.o roarx11.o beep.o proto.o env.o keyval.o vs.o ltm.o notify.o notify_proxy.o asyncctl.o enumdev.o serverinfo.o $(CRYPTO) authfile.o caps.o roarfloat.o base64.o trap.o memmgr.o time.o kstore.o uuid.o watchdog.o
+OBJS=libroar.o config.o debug.o error.o basic.o stream.o client.o simple.o auth.o socket.o ctl.o buffer.o meta.o file.o acl.o cdrom.o $(PASSWORD) $(VIO) stack.o slp.o nnode.o roardl.o plugincontainer.o roarx11.o beep.o proto.o env.o keyval.o vs.o ltm.o notify.o notify_proxy.o asyncctl.o enumdev.o serverinfo.o $(CRYPTO) authfile.o caps.o roarfloat.o base64.o trap.o memmgr.o time.o kstore.o uuid.o watchdog.o scheduler.o
 
 #DEFINES        = -DDEBUG
Index: libroar/scheduler.c
===================================================================
--- libroar/scheduler.c	(revision 5692)
+++ libroar/scheduler.c	(revision 5692)
@@ -0,0 +1,635 @@
+//scheduler.c:
+
+/*
+ *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2012
+ *
+ *  This file is part of libroar a part of RoarAudio,
+ *  a cross-platform sound system for both, home and professional use.
+ *  See README for details.
+ *
+ *  This file is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3
+ *  as published by the Free Software Foundation.
+ *
+ *  libroar is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ *
+ *  NOTE for everyone want's to change something and send patches:
+ *  read README and HACKING! There a addition information on
+ *  the license of this document you need to read before you send
+ *  any patches.
+ *
+ *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
+ *  or libpulse*:
+ *  The libs libroaresd, libroararts and libroarpulse link this lib
+ *  and are therefore GPL. Because of this it may be illigal to use
+ *  them with any software that uses libesd, libartsc or libpulse*.
+ */
+
+#include "libroar.h"
+
+#define INIT_SIZE   8
+#define MAX_PROTOS 16
+
+struct protocol {
+ const struct roar_keyval * para;
+ ssize_t paralen;
+ struct roar_dl_lhandle * lhandle;
+ const struct roar_dl_proto * impl;
+};
+
+struct roar_scheduler {
+ size_t refc;
+ struct roar_scheduler_source ** sources;
+ size_t sources_len;
+ struct roar_vio_select * vios;
+ size_t vios_len;
+ struct roar_dl_fnreg callback;
+ struct protocol protos[MAX_PROTOS];
+};
+
+struct roar_scheduler * roar_scheduler_new(void) {
+ struct roar_scheduler * sched = roar_mm_malloc(sizeof(struct roar_scheduler));
+
+ if ( sched == NULL )
+  return NULL;
+
+ memset(sched, 0, sizeof(struct roar_scheduler));
+ sched->refc = 1;
+
+ sched->sources = roar_mm_malloc(INIT_SIZE*sizeof(struct roar_scheduler_source *));
+ if ( sched->sources != NULL ) {
+  sched->sources_len = INIT_SIZE;
+  memset(sched->sources, 0, INIT_SIZE*sizeof(struct roar_scheduler_source *));
+ }
+
+ sched->vios = roar_mm_malloc(sched->sources_len*sizeof(struct roar_vio_select));
+ if ( sched->vios != 0 )
+  sched->vios_len = sched->sources_len;
+
+ return sched;
+}
+
+#define _CHKSCHED(extra) if ( sched == NULL || (extra) ) { roar_err_set(ROAR_ERROR_FAULT); return -1; }
+
+int                     roar_scheduler_ref(struct roar_scheduler * sched) {
+ _CHKSCHED(0);
+
+ sched->refc++;
+
+ return 0;
+}
+
+int                     roar_scheduler_unref(struct roar_scheduler * sched) {
+ size_t i;
+
+ _CHKSCHED(0);
+
+ sched->refc--;
+
+ if (sched->refc)
+  return 0;
+
+ for (i = 0; i < sched->sources_len; i++)
+  if ( sched->sources[i] != NULL )
+   roar_scheduler_source_del(sched, sched->sources[i]);
+
+ if ( sched->vios != NULL )
+  roar_mm_free(sched->vios);
+ if ( sched->sources != NULL )
+  roar_mm_free(sched->sources);
+ roar_mm_free(sched);
+ return 0;
+}
+
+static void __delete_cpi_client(struct roar_scheduler * sched, struct roar_scheduler_source * cur, struct roar_dl_librarypara * para) {
+ if ( cur->handle.cpi.impl->unset_proto != NULL )
+  cur->handle.cpi.impl->unset_proto(cur->handle.cpi.client, cur->vio, &(cur->handle.cpi.obuffer), &(cur->handle.cpi.userdata), cur->handle.cpi.protopara, cur->handle.cpi.protoparalen, para);
+
+ roar_vio_close(cur->vio);
+ cur->vio = NULL;
+
+ if ( cur->handle.cpi.obuffer != NULL ) {
+  roar_buffer_free(cur->handle.cpi.obuffer);
+  cur->handle.cpi.obuffer = NULL;
+ }
+
+ if ( cur->handle.cpi.userdata != NULL ) {
+  roar_mm_free(cur->handle.cpi.userdata);
+  cur->handle.cpi.userdata = NULL;
+ }
+
+ roar_scheduler_source_del(sched, cur);
+}
+
+static int __flush_cpi_client(struct roar_scheduler * sched, struct roar_scheduler_source * cur, struct roar_dl_librarypara * para) {
+ size_t len;
+ ssize_t ret;
+ void * buf;
+
+ if ( roar_buffer_get_len(cur->handle.cpi.obuffer, &len) == -1 )
+  return 0;
+
+ if ( roar_buffer_get_data(cur->handle.cpi.obuffer, &buf) == -1 )
+  return 0;
+
+ ret = roar_vio_write(cur->vio, buf, len);
+
+ if ( ret < 1 )
+  return -1;
+
+ if ( ret == (ssize_t)len ) {
+  if ( roar_buffer_next(&(cur->handle.cpi.obuffer)) == -1 )
+   return -1;
+ } else {
+  if ( roar_buffer_set_offset(cur->handle.cpi.obuffer, ret) == -1 )
+   return -1;
+ }
+
+ return 0;
+}
+
+// what to do?:
+// 0. get all VIOs.
+// 1. get timeout or use internal default.
+// 2. run roar_vio_select().
+// 3. send all events based on results.
+// 4. send UPDATE to all plugins and containers.
+int                     roar_scheduler_iterate(struct roar_scheduler * sched) {
+ struct roar_vio_selecttv timeout = {8, 0}; // default: 8 sec. Just a random value.
+ struct roar_scheduler_source * cur, * new_client;
+ struct roar_dl_librarypara * para;
+ struct roar_dl_lhandle * lhandle;
+ ssize_t ret;
+ size_t i;
+ int have_timeout = 0;
+ size_t todo = 0;
+ int tmp;
+
+ _CHKSCHED(0);
+
+ if ( sched->vios == NULL || sched->vios_len < sched->sources_len ) {
+  if ( sched->vios != NULL ) {
+   roar_mm_free(sched->vios);
+   sched->vios = NULL;
+   sched->vios_len = 0;
+  }
+
+  sched->vios = roar_mm_malloc(sched->sources_len*sizeof(struct roar_vio_select));
+  if ( sched->vios != NULL )
+   sched->vios_len = sched->sources_len;
+ }
+
+ // error from roar_mm_malloc() is still set.
+ if ( sched->vios == NULL )
+  return -1;
+
+ memset(sched->vios, 0, sched->vios_len*sizeof(struct roar_vio_select));
+ for (i = 0; i < sched->vios_len; i++)
+  sched->vios[i].eventsq = ROAR_VIO_SELECT_NO_RETEST;
+
+ for (i = 0; i < sched->sources_len; i++) {
+  if ( (cur = sched->sources[i]) == NULL )
+   continue;
+  switch (cur->type) {
+   case ROAR_SCHEDULER_VIO:
+     ROAR_VIO_SELECT_SETVIO(&(sched->vios[i]), cur->vio, cur->handle.eventsq);
+     todo++;
+    break;
+   case ROAR_SCHEDULER_TIMEOUT:
+     timeout = cur->handle.timeout;
+     have_timeout = 1;
+     todo++;
+    break;
+   case ROAR_SCHEDULER_CPI_LISTEN:
+     ROAR_VIO_SELECT_SETVIO(&(sched->vios[i]), cur->vio, ROAR_VIO_SELECT_READ);
+     todo++;
+    break;
+   case ROAR_SCHEDULER_CPI_CLIENT:
+     tmp = 0;
+
+     if ( cur->handle.cpi.impl->status != NULL ) {
+      if ( cur->lhandle != NULL )
+       roar_dl_context_restore(cur->lhandle);
+
+      para = roar_dl_getpara(cur->lhandle);
+      if ( cur->handle.cpi.impl->status(cur->handle.cpi.client, cur->vio, &(cur->handle.cpi.obuffer), &(cur->handle.cpi.userdata), cur->handle.cpi.protopara, cur->handle.cpi.protoparalen, para) & ROAR_DL_PROTO_STATUS_RX_READY )
+       tmp |= ROAR_VIO_SELECT_READ;
+      if ( para != NULL )
+       roar_dl_para_unref(para);
+
+      if ( cur->lhandle != NULL )
+       roar_dl_context_store(cur->lhandle);
+     } else {
+      tmp |= ROAR_VIO_SELECT_READ;
+     }
+
+     if ( sched->sources[i]->handle.cpi.obuffer != NULL )
+      tmp |= ROAR_VIO_SELECT_WRITE;
+
+     ROAR_VIO_SELECT_SETVIO(&(sched->vios[i]), sched->sources[i]->vio, tmp);
+     todo++;
+    break;
+   case ROAR_SCHEDULER_PLUGIN:
+   case ROAR_SCHEDULER_PLUGINCONTAINER:
+     todo++;
+    break;
+#ifndef DEBUG
+   default: /* noop */ break;
+#endif
+  }
+ }
+
+ if (!todo) {
+  roar_err_set(ROAR_ERROR_NOENT);
+  return 0;
+ }
+
+ ret = roar_vio_select(sched->vios, sched->vios_len, &timeout, NULL);
+ if ( ret == -1 )
+  return -1;
+ if ( ret == 0 && !have_timeout )
+  return 1;
+
+ for (i = 0; i < sched->sources_len; i++) {
+  if ( (cur = sched->sources[i]) == NULL )
+   continue;
+  switch (cur->type) {
+   case ROAR_SCHEDULER_VIO:
+     if ( sched->vios[i].eventsa )
+      if ( cur->cb != NULL )
+       cur->cb(sched->sources[i], sched->sources[i]->userdata, sched->vios[i].eventsa);
+    break;
+   case ROAR_SCHEDULER_TIMEOUT:
+     if ( ret == 0 )
+      if ( cur->cb != NULL )
+       cur->cb(sched->sources[i], sched->sources[i]->userdata, 0);
+    break;
+   case ROAR_SCHEDULER_PLUGIN:
+     roar_dl_appsched_trigger(cur->lhandle, ROAR_DL_APPSCHED_UPDATE);
+    break;
+   case ROAR_SCHEDULER_PLUGINCONTAINER:
+     roar_plugincontainer_appsched_trigger(cur->handle.container, ROAR_DL_APPSCHED_UPDATE);
+    break;
+   case ROAR_SCHEDULER_CPI_LISTEN:
+     if ( !sched->vios[i].eventsa )
+      continue;
+
+     if ( cur->cb != NULL )
+      cur->cb(sched->sources[i], sched->sources[i]->userdata, sched->vios[i].eventsa);
+
+     new_client = roar_mm_malloc(sizeof(struct roar_scheduler_source));
+     if ( new_client == NULL )
+      continue;
+     memcpy(new_client, cur, sizeof(struct roar_scheduler_source));
+     new_client->type = ROAR_SCHEDULER_CPI_CLIENT;
+     new_client->flags = ROAR_SCHEDULER_FLAG_FREE;
+     new_client->vio   = roar_mm_malloc(sizeof(struct roar_vio_calls));
+
+     if ( new_client->vio == NULL ) {
+      roar_mm_free(new_client);
+      continue;
+     }
+
+     if ( roar_vio_accept(new_client->vio, cur->vio) == -1 ) {
+      roar_mm_free(new_client->vio);
+      roar_mm_free(new_client);
+      continue;
+     }
+
+     new_client->vio->flags |= ROAR_VIO_FLAGS_FREESELF;
+
+     if ( roar_scheduler_source_add(sched, new_client) == -1 ) {
+      roar_vio_close(new_client->vio);
+      roar_mm_free(new_client);
+     }
+     roar_vio_unref(new_client->vio);
+
+     if ( new_client->cb != NULL )
+      new_client->cb(new_client, new_client->userdata, 0);
+
+     if ( cur->handle.cpi.impl->set_proto != NULL ) {
+      lhandle = new_client->lhandle;
+      para = roar_dl_getpara(lhandle);
+
+      if ( lhandle != NULL )
+       roar_dl_context_restore(lhandle);
+      new_client->handle.cpi.impl->set_proto(new_client->handle.cpi.client, new_client->vio, &(new_client->handle.cpi.obuffer), &(new_client->handle.cpi.userdata), new_client->handle.cpi.protopara, new_client->handle.cpi.protoparalen, para);
+      if ( lhandle != NULL )
+       roar_dl_context_store(lhandle);
+
+      if ( para != NULL )
+       roar_dl_para_unref(para);
+     }
+    break;
+   case ROAR_SCHEDULER_CPI_CLIENT:
+     if ( !sched->vios[i].eventsa )
+      continue;
+
+     if ( cur->cb != NULL )
+      cur->cb(sched->sources[i], sched->sources[i]->userdata, sched->vios[i].eventsa);
+
+     lhandle = cur->lhandle;
+     para = roar_dl_getpara(lhandle);
+     tmp = 0;
+
+     if ( sched->vios[i].eventsa & ROAR_VIO_SELECT_WRITE ) {
+      if ( cur->handle.cpi.impl->flush != NULL ) {
+       if ( lhandle != NULL )
+        roar_dl_context_restore(lhandle);
+
+       cur->handle.cpi.impl->flush(cur->handle.cpi.client, cur->vio, &(cur->handle.cpi.obuffer), &(cur->handle.cpi.userdata), cur->handle.cpi.protopara, cur->handle.cpi.protoparalen, para);
+
+       if ( lhandle != NULL )
+        roar_dl_context_store(lhandle);
+      } else {
+        tmp = __flush_cpi_client(sched, cur, para);
+      }
+
+      if ( tmp == 0 && cur->handle.cpi.obuffer == NULL && cur->handle.cpi.impl->flushed != NULL ) {
+       if ( lhandle != NULL )
+        roar_dl_context_restore(lhandle);
+
+       cur->handle.cpi.impl->flushed(cur->handle.cpi.client, cur->vio, &(cur->handle.cpi.obuffer), &(cur->handle.cpi.userdata), cur->handle.cpi.protopara, cur->handle.cpi.protoparalen, para);
+
+       if ( lhandle != NULL )
+        roar_dl_context_store(lhandle);
+      }
+     }
+
+     if ( sched->vios[i].eventsa & ROAR_VIO_SELECT_READ ) {
+      if ( cur->handle.cpi.impl->handle != NULL ) {
+       if ( lhandle != NULL )
+        roar_dl_context_restore(lhandle);
+
+       if ( cur->handle.cpi.impl->handle(cur->handle.cpi.client, cur->vio, &(cur->handle.cpi.obuffer), &(cur->handle.cpi.userdata), cur->handle.cpi.protopara, cur->handle.cpi.protoparalen, para) == -1 ) {
+        tmp = -1;
+       }
+
+       if ( lhandle != NULL )
+        roar_dl_context_store(lhandle);
+      }
+     }
+
+     if ( tmp == -1 ) {
+      if ( lhandle != NULL )
+       roar_dl_context_restore(lhandle);
+      __delete_cpi_client(sched, cur, para);
+      if ( lhandle != NULL )
+       roar_dl_context_store(lhandle);
+     }
+
+     if ( para != NULL )
+      roar_dl_para_unref(para);
+    break;
+#ifndef DEBUG
+   default: /* noop */ break;
+#endif
+  }
+ }
+
+ return 1;
+}
+
+int                     roar_scheduler_run(struct roar_scheduler * sched) {
+ int ret;
+
+ _CHKSCHED(0);
+
+ while ((ret = roar_scheduler_iterate(sched)) > 0);
+
+ return ret;
+}
+
+static int __cpi_callback(enum roar_dl_fnreg_action action, int fn, int subtype, const void * object, size_t objectlen, int version, int options, void * userdata, struct roar_dl_lhandle * lhandle) {
+ const struct roar_dl_proto * impl = object;
+ struct roar_scheduler * sched = userdata;
+ struct roar_dl_librarypara * para;
+ size_t i;
+
+ (void)fn, (void)subtype, (void)version, (void)options;
+
+ if ( sched == NULL ) {
+  roar_err_set(ROAR_ERROR_FAULT);
+  return -1;
+ }
+
+ if ( objectlen != ROAR_DL_PROTO_SIZE ) {
+  ROAR_WARN("__cpi_callback(*): Library %p tries to register protocol with bad object length.", lhandle);
+  roar_err_set(ROAR_ERROR_BADLIB);
+  return -1;
+ }
+
+ switch (action)  {
+  case ROAR_DL_FNREG:
+    for (i = 0; i < MAX_PROTOS; i++) {
+     if ( sched->protos[i].impl == NULL ) {
+      memset(&(sched->protos[i]), 0, sizeof(sched->protos[i]));
+      sched->protos[i].para = NULL;
+      sched->protos[i].paralen = -1;
+      sched->protos[i].lhandle = lhandle;
+      sched->protos[i].impl = impl;
+      return 0;
+     }
+    }
+   break;
+  case ROAR_DL_FNUNREG:
+    for (i = 0; i < sched->sources_len; i++) {
+     if ( sched->sources[i] == NULL )
+      continue;
+     if ( sched->sources[i]->type != ROAR_SCHEDULER_CPI_LISTEN && sched->sources[i]->type != ROAR_SCHEDULER_CPI_CLIENT )
+      continue;
+     if ( sched->sources[i]->handle.cpi.proto != impl->proto )
+      continue;
+
+     para = roar_dl_getpara(lhandle);
+
+     if ( lhandle != NULL )
+      roar_dl_context_restore(lhandle);
+     __delete_cpi_client(sched, sched->sources[i], para);
+     if ( lhandle != NULL )
+      roar_dl_context_store(lhandle);
+
+     if ( para != NULL )
+      roar_dl_para_unref(para);
+    }
+
+    for (i = 0; i < MAX_PROTOS; i++) {
+     if ( sched->protos[i].impl != NULL && sched->protos[i].lhandle == lhandle ) {
+      memset(&(sched->protos[i]), 0, sizeof(sched->protos[i]));
+      sched->protos[i].impl = NULL;
+     }
+    }
+    return 0;
+   break;
+ }
+
+ roar_err_set(ROAR_ERROR_NOSPC);
+ return -1;
+}
+
+static int __update_cpi_service (struct roar_scheduler * sched, struct roar_scheduler_source * source, int del) {
+ if ( del ) {
+  roar_err_set(ROAR_ERROR_NOTSUP);
+  return -1;
+ }
+
+ sched->callback.fn = ROAR_DL_FN_PROTO;
+ sched->callback.subtype = ROAR_DL_PROTO_SUBTYPE;
+ sched->callback.version = ROAR_DL_PROTO_VERSION;
+ sched->callback.callback = __cpi_callback;
+ sched->callback.userdata = sched;
+
+ ROAR_DL_RFNREG(ROAR_DL_HANDLE_LIBROAR, sched->callback);
+
+ return -1;
+}
+
+static int __update_cpi_listen_client (struct roar_scheduler * sched, struct roar_scheduler_source * source) {
+ size_t i;
+
+ ROAR_DBG("__update_cpi_listen_client(sched=%p, source=%p): proto=%i, impl=%p", sched, source, source->handle.cpi.proto, source->handle.cpi.impl);
+
+ if ( source->handle.cpi.proto < 1 && source->handle.cpi.impl != NULL )
+  source->handle.cpi.proto = source->handle.cpi.impl->proto;
+
+ if ( source->handle.cpi.proto > 0 && source->handle.cpi.impl == NULL ) {
+  for (i = 0; i < MAX_PROTOS; i++) {
+   if ( sched->protos[i].impl == NULL )
+    continue;
+   ROAR_DBG("__update_cpi_listen_client(sched=%p, source=%p): proto=%i<->%i", sched, source, sched->protos[i].impl->proto, source->handle.cpi.proto);
+   if ( sched->protos[i].impl->proto != source->handle.cpi.proto )
+    continue;
+   source->handle.cpi.impl = sched->protos[i].impl;
+   break;
+  }
+ }
+
+ if ( source->handle.cpi.proto > 0 && source->handle.cpi.impl != NULL )
+  return 0;
+
+ roar_err_set(ROAR_ERROR_INVAL);
+ return -1;
+}
+
+int                     roar_scheduler_source_add(struct roar_scheduler * sched,
+                                                  struct roar_scheduler_source * source) {
+ size_t i;
+ struct roar_scheduler_source ** next = NULL;
+ int err;
+ 
+ _CHKSCHED(source == NULL);
+
+ ROAR_DBG("roar_scheduler_source_add(sched=%p, source=%p): proto=%i, impl=%p", sched, source, source->handle.cpi.proto, source->handle.cpi.impl);
+
+ for (i = 0; i < sched->sources_len; i++) {
+  if ( sched->sources[i] != NULL )
+   continue;
+  next = &(sched->sources[i]);
+  break;
+ }
+
+ if ( next == NULL ) {
+  // TODO: re-allocate some space here.
+  roar_err_set(ROAR_ERROR_NOSPC);
+  return -1;
+ }
+
+ switch (source->type) {
+  case ROAR_SCHEDULER_CPI_LISTEN:
+  case ROAR_SCHEDULER_CPI_CLIENT:
+    if ( __update_cpi_listen_client(sched, source) == -1 )
+     return -1;
+   break;
+  case ROAR_SCHEDULER_CPI_SERVICE:
+    if ( __update_cpi_service(sched, source, 0) == -1 )
+     return -1;
+   break;
+#ifndef DEBUG
+   default: /* noop */ break;
+#endif
+ }
+
+ if ( source->lhandle != NULL )
+  if ( roar_dl_ref(source->lhandle) == -1 )
+   return -1;
+
+ if ( source->vio != NULL ) {
+  if ( roar_vio_ref(source->vio) == -1 ) {
+   err = roar_error;
+   if ( source->lhandle != NULL )
+    roar_dl_unref(source->lhandle);
+   roar_err_set(err);
+   return -1;
+  }
+ }
+
+ if ( source->type == ROAR_SCHEDULER_PLUGINCONTAINER ) {
+  if ( roar_plugincontainer_ref(source->handle.container) == -1 ) {
+   err = roar_error;
+   if ( source->lhandle != NULL )
+    roar_dl_unref(source->lhandle);
+   if ( source->vio != NULL )
+    roar_vio_unref(source->vio);
+   roar_err_set(err);
+   return -1;
+  }
+ }
+
+ *next = source;
+
+ return 0;
+}
+
+int                     roar_scheduler_source_del(struct roar_scheduler * sched,
+                                                  struct roar_scheduler_source * source) {
+ size_t i;
+ struct roar_scheduler_source ** next = NULL;
+
+ _CHKSCHED(source == NULL);
+
+ for (i = 0; i < sched->sources_len; i++) {
+  if ( sched->sources[i] != source )
+   continue;
+  next = &(sched->sources[i]);
+  break;
+ }
+
+ if ( next == NULL ) {
+  roar_err_set(ROAR_ERROR_NOENT);
+  return -1;
+ }
+
+ switch (source->type) {
+  case ROAR_SCHEDULER_PLUGINCONTAINER:
+    roar_plugincontainer_ref(source->handle.container);
+   break;
+  case ROAR_SCHEDULER_CPI_SERVICE:
+    if ( __update_cpi_service(sched, source, 1) == -1 )
+     return -1;
+   break;
+#ifndef DEBUG
+   default: /* noop */ break;
+#endif
+ }
+
+ if ( source->lhandle != NULL )
+  roar_dl_unref(source->lhandle);
+ if ( source->vio != NULL )
+  roar_vio_unref(source->vio);
+
+ if ( source->flags & ROAR_SCHEDULER_FLAG_FREE )
+  roar_mm_free(source);
+
+ *next = NULL;
+ return 0;
+}
+
+//ll
