updates.
authorPekka Riikonen <priikone@silcnet.org>
Tue, 17 Jul 2001 22:21:01 +0000 (22:21 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Tue, 17 Jul 2001 22:21:01 +0000 (22:21 +0000)
27 files changed:
CHANGES
TODO
apps/silcd/command.c
apps/silcd/idlist.c
apps/silcd/idlist.h
apps/silcd/packet_receive.c
apps/silcd/protocol.c
apps/silcd/server.c
apps/silcd/server.h
apps/silcd/server_internal.h
includes/silcincludes.h
lib/silcclient/client.c
lib/silcclient/client.h
lib/silcclient/client_keyagr.c
lib/silcclient/command.c
lib/silcclient/protocol.c
lib/silccore/silcprotocol.c
lib/silccore/silcprotocol.h
lib/silcutil/Makefile.am
lib/silcutil/silcschedule.c
lib/silcutil/silcschedule.h
lib/silcutil/silcsockconn.c
lib/silcutil/silcsockconn.h
lib/silcutil/silctask.c [deleted file]
lib/silcutil/silctask.h [deleted file]
lib/silcutil/unix/silcunixschedule.c
lib/silcutil/win32/silcwin32schedule.c

diff --git a/CHANGES b/CHANGES
index 4b2e4006be6aae03ca40b4be20ddc4008eebcd5c..db43190d0bf14138df3472b5add391b0487ebcff 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,12 @@
+Tue Jul 17 23:04:10 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
+
+       * Rewrote the SILC Scheduler entirely.  Removed the old SILC Task
+         API.  It is part of the scheduler now.  Everything else is
+         as previously but some functions has changed their names.
+         Checkout the lib/silcutil/silcschedule.h for the interface.
+         Updated all applications to use the new interface.  Affected
+         files are lib/silcutil/silcschedule.[ch].
+
 Tue Jul 17 16:53:30 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * Found a bug in the SKE implementation.  The HASH value,
@@ -7,6 +16,15 @@ Tue Jul 17 16:53:30 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
          This unfortunately causes incompatibilities with older
          clients and servers.
 
+       * Added WIN32 specific network init and uninit functions:
+         silc_net_win32_init and silc_net_win32_uninit to init and uninit
+         the Winsock2.  Affected file lib/silcutil/silcnet.h and
+         lib/silcutil/win32/silcwin32net.c.
+
+       * Set the socket always to nonblocking mode on WIN32 after
+         reading data or writing data.  Affected file is
+         lib/silcutil/win32/silcwin32sockconn.c.
+
 Mon Jul 16 22:55:26 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * Fixed various compilation problems under WIN32.  Affected
diff --git a/TODO b/TODO
index 1bb758dc0e0c8a211d595a9a403700236307ba77..08837155f8879de4b5009c6a554826ffc23c5aea 100644 (file)
--- a/TODO
+++ b/TODO
@@ -109,6 +109,8 @@ TODO/Bugs in native WIN32 support (libraries)
  o silc_net_create_connection_async does not work the same way than on
    Unix.  Do it with threads on WIN32.
 
+ o SHA1 implementation is broken on WIN32 MSVC++.
+
 
 TODO In SILC Protocol
 =====================
index 14a6550fa6b02dda1c7313b28970c7547fa3bf34..b0207cfa8d5e96c777c9a87d3d90840867ae423c 100644 (file)
@@ -224,14 +224,14 @@ void silc_server_command_process(SilcServer server,
 
     if (!fast && ((cmd->flags & SILC_CF_LAG_STRICT) ||
                  (client->fast_command > 5 && cmd->flags & SILC_CF_LAG)))
-      silc_task_register(server->timeout_queue, sock->sock, 
+      silc_schedule_task_add(server->schedule, sock->sock, 
                         silc_server_command_process_timeout,
                         (void *)timeout, 
                         2 - (time(NULL) - client->last_command), 0,
                         SILC_TASK_TIMEOUT,
                         SILC_TASK_PRI_NORMAL);
     else
-      silc_task_register(server->timeout_queue, sock->sock, 
+      silc_schedule_task_add(server->schedule, sock->sock, 
                         silc_server_command_process_timeout,
                         (void *)timeout, 
                         0, 1,
@@ -2428,7 +2428,7 @@ SILC_SERVER_CMD_FUNC(quit)
   q->signoff = tmp ? strdup(tmp) : NULL;
 
   /* We quit the connection with little timeout */
-  silc_task_register(server->timeout_queue, sock->sock,
+  silc_schedule_task_add(server->schedule, sock->sock,
                     silc_server_command_quit_cb, (void *)q,
                     0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
index 0d7ed54d5235f49f241d30b914e29f0e25eec442..3a00463200b8d804e31c9becab6ebdf5d110733c 100644 (file)
@@ -77,10 +77,10 @@ SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge)
   SILC_LOG_DEBUG(("Start"));
 
   silc_idcache_purge(i->cache);
-  silc_task_register(i->timeout_queue, 0, 
-                    silc_idlist_purge,
-                    (void *)i, 600, 0,
-                    SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+  silc_schedule_task_add(i->schedule, 0, 
+                        silc_idlist_purge,
+                        (void *)i, 600, 0,
+                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 }
 
 /******************************************************************************
index f701514bc7fd6314b7f61cc72bfbc0efd469b92b..0f0cb3e778506806ebda5835e6afcf13d3369a0a 100644 (file)
@@ -30,7 +30,7 @@ typedef struct SilcChannelEntryStruct *SilcChannelEntry;
    the cache. */
 typedef struct {
   SilcIDCache cache;
-  void *timeout_queue;
+  SilcSchedule schedule;
 } *SilcIDListPurge;
 
 /* Channel key re-key context. */
index 51ff706ee3b06c9b6158aafbeeadb52535dab3b0..f0b6c09117647c79520b8c7d749c3a9fe2954234 100644 (file)
@@ -2184,5 +2184,5 @@ void silc_server_rekey(SilcServer server,
 
   if (proto_ctx->pfs == FALSE)
     /* Run the protocol */
-    silc_protocol_execute(protocol, server->timeout_queue, 0, 0);
+    silc_protocol_execute(protocol, server->schedule, 0, 0);
 }
index 0a720081d69db1a4275033bc40d6ebf5fd3d3e5d..8bf9e5b96e9dcee1d401cc6283a933e747dc00cc 100644 (file)
@@ -365,7 +365,7 @@ static void silc_server_protocol_ke_continue(SilcSKE ske, void *context)
                    ske->status));
     
     protocol->state = SILC_PROTOCOL_STATE_ERROR;
-    silc_protocol_execute(protocol, server->timeout_queue, 0, 300000);
+    silc_protocol_execute(protocol, server->schedule, 0, 300000);
     return;
   }
 
@@ -383,7 +383,7 @@ static void silc_server_protocol_ke_continue(SilcSKE ske, void *context)
      function. */
   if (ctx->responder == TRUE) {
     protocol->state++;
-    silc_protocol_execute(protocol, server->timeout_queue, 0, 100000);
+    silc_protocol_execute(protocol, server->schedule, 0, 100000);
   }
 }
 
@@ -455,14 +455,14 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
                        status));
 
        protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, server->timeout_queue, 0, 300000);
+       silc_protocol_execute(protocol, server->schedule, 0, 300000);
        return;
       }
 
       /* Advance protocol state and call the next state if we are responder */
       protocol->state++;
       if (ctx->responder == TRUE)
-       silc_protocol_execute(protocol, server->timeout_queue, 0, 100000);
+       silc_protocol_execute(protocol, server->schedule, 0, 100000);
     }
     break;
   case 2:
@@ -493,14 +493,14 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
                        status));
 
        protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, server->timeout_queue, 0, 300000);
+       silc_protocol_execute(protocol, server->schedule, 0, 300000);
        return;
       }
 
       /* Advance protocol state and call next state if we are initiator */
       protocol->state++;
       if (ctx->responder == FALSE)
-       silc_protocol_execute(protocol, server->timeout_queue, 0, 100000);
+       silc_protocol_execute(protocol, server->schedule, 0, 100000);
     }
     break;
   case 3:
@@ -535,7 +535,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
                        status));
 
        protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, server->timeout_queue, 0, 300000);
+       silc_protocol_execute(protocol, server->schedule, 0, 300000);
        return;
       }
     }
@@ -573,7 +573,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
                        status));
 
        protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, server->timeout_queue, 0, 300000);
+       silc_protocol_execute(protocol, server->schedule, 0, 300000);
        return;
       }
     }
@@ -594,7 +594,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
                                             keymat);
       if (status != SILC_SKE_STATUS_OK) {
        protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, server->timeout_queue, 0, 300000);
+       silc_protocol_execute(protocol, server->schedule, 0, 300000);
        silc_ske_free_key_material(keymat);
        return;
       }
@@ -609,11 +609,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
         This was the timeout task to be executed if the protocol is
         not completed fast enough. */
       if (ctx->timeout_task)
-       silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+       silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
       /* Call the final callback */
       if (protocol->final_callback)
-       silc_protocol_execute_final(protocol, server->timeout_queue);
+       silc_protocol_execute_final(protocol, server->schedule);
       else
        silc_protocol_free(protocol);
     }
@@ -631,11 +631,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
        This was the timeout task to be executed if the protocol is
        not completed fast enough. */
     if (ctx->timeout_task)
-      silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+      silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
     /* On error the final callback is always called. */
     if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, server->timeout_queue);
+      silc_protocol_execute_final(protocol, server->schedule);
     else
       silc_protocol_free(protocol);
     break;
@@ -649,11 +649,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
        This was the timeout task to be executed if the protocol is
        not completed fast enough. */
     if (ctx->timeout_task)
-      silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+      silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
     /* On error the final callback is always called. */
     if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, server->timeout_queue);
+      silc_protocol_execute_final(protocol, server->schedule);
     else
       silc_protocol_free(protocol);
     break;
@@ -811,14 +811,14 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
        if (ret == -1) {
          SILC_LOG_DEBUG(("Bad payload in authentication packet"));
          protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, server->timeout_queue, 0, 300000);
+         silc_protocol_execute(protocol, server->schedule, 0, 300000);
          return;
        }
        
        if (payload_len != ctx->packet->buffer->len) {
          SILC_LOG_DEBUG(("Bad payload in authentication packet"));
          protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, server->timeout_queue, 0, 300000);
+         silc_protocol_execute(protocol, server->schedule, 0, 300000);
          return;
        }
        
@@ -828,7 +828,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
            conn_type > SILC_SOCKET_TYPE_ROUTER) {
          SILC_LOG_ERROR(("Bad connection type %d", conn_type));
          protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, server->timeout_queue, 0, 300000);
+         silc_protocol_execute(protocol, server->schedule, 0, 300000);
          return;
        }
        
@@ -842,7 +842,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
          if (ret == -1) {
            SILC_LOG_DEBUG(("Bad payload in authentication packet"));
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, server->timeout_queue, 0, 300000);
+           silc_protocol_execute(protocol, server->schedule, 0, 300000);
            return;
          }
        }
@@ -880,7 +880,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
              SILC_LOG_DEBUG(("Authentication failed"));
              silc_free(auth_data);
              protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->timeout_queue, 
+             silc_protocol_execute(protocol, server->schedule, 
                                    0, 300000);
              return;
              break;
@@ -901,7 +901,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
              SILC_LOG_DEBUG(("Authentication failed"));
              silc_free(auth_data);
              protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->timeout_queue, 
+             silc_protocol_execute(protocol, server->schedule, 
                                    0, 300000);
              return;
            }
@@ -911,7 +911,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
            SILC_LOG_ERROR(("Authentication failed"));
            silc_free(auth_data);
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, server->timeout_queue, 
+           silc_protocol_execute(protocol, server->schedule, 
                                  0, 300000);
            return;
          }
@@ -942,7 +942,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
              SILC_LOG_DEBUG(("Authentication failed"));
              silc_free(auth_data);
              protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->timeout_queue, 
+             silc_protocol_execute(protocol, server->schedule, 
                                    0, 300000);
              return;
              break;
@@ -963,7 +963,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
              SILC_LOG_DEBUG(("Authentication failed"));
              silc_free(auth_data);
              protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->timeout_queue, 
+             silc_protocol_execute(protocol, server->schedule, 
                                    0, 300000);
              return;
            }
@@ -972,7 +972,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
            SILC_LOG_ERROR(("Remote connection not configured"));
            SILC_LOG_ERROR(("Authentication failed"));
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, server->timeout_queue, 
+           silc_protocol_execute(protocol, server->schedule, 
                                  0, 300000);
            silc_free(auth_data);
            return;
@@ -1004,7 +1004,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
              SILC_LOG_DEBUG(("Authentication failed"));
              silc_free(auth_data);
              protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->timeout_queue, 
+             silc_protocol_execute(protocol, server->schedule, 
                                    0, 300000);
              return;
              break;
@@ -1025,7 +1025,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
              SILC_LOG_DEBUG(("Authentication failed"));
              silc_free(auth_data);
              protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->timeout_queue, 
+             silc_protocol_execute(protocol, server->schedule, 
                                    0, 300000);
              return;
            }
@@ -1035,7 +1035,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
            SILC_LOG_ERROR(("Authentication failed"));
            silc_free(auth_data);
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, server->timeout_queue, 
+           silc_protocol_execute(protocol, server->schedule, 
                                  0, 300000);
            return;
          }
@@ -1049,7 +1049,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
          
        /* Advance protocol state. */
        protocol->state = SILC_PROTOCOL_STATE_END;
-       silc_protocol_execute(protocol, server->timeout_queue, 0, 0);
+       silc_protocol_execute(protocol, server->schedule, 0, 0);
 
       } else {
        /* 
@@ -1136,11 +1136,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
         This was the timeout task to be executed if the protocol is
         not completed fast enough. */
       if (ctx->timeout_task)
-       silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+       silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
       /* Protocol has ended, call the final callback */
       if (protocol->final_callback)
-       silc_protocol_execute_final(protocol, server->timeout_queue);
+       silc_protocol_execute_final(protocol, server->schedule);
       else
        silc_protocol_free(protocol);
     }
@@ -1162,11 +1162,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
         This was the timeout task to be executed if the protocol is
         not completed fast enough. */
       if (ctx->timeout_task)
-       silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+       silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
       /* On error the final callback is always called. */
       if (protocol->final_callback)
-       silc_protocol_execute_final(protocol, server->timeout_queue);
+       silc_protocol_execute_final(protocol, server->schedule);
       else
        silc_protocol_free(protocol);
     }
@@ -1181,11 +1181,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
        This was the timeout task to be executed if the protocol is
        not completed fast enough. */
     if (ctx->timeout_task)
-      silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+      silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
     /* On error the final callback is always called. */
     if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, server->timeout_queue);
+      silc_protocol_execute_final(protocol, server->schedule);
     else
       silc_protocol_free(protocol);
     break;
@@ -1372,7 +1372,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
          if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_1) {
            /* Error in protocol */
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, server->timeout_queue, 0, 300000);
+           silc_protocol_execute(protocol, server->schedule, 0, 300000);
          }
 
          ctx->ske = silc_ske_alloc();
@@ -1392,13 +1392,13 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
                              status));
            
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, server->timeout_queue, 0, 300000);
+           silc_protocol_execute(protocol, server->schedule, 0, 300000);
            return;
          }
 
          /* Advance the protocol state */
          protocol->state++;
-         silc_protocol_execute(protocol, server->timeout_queue, 0, 0);
+         silc_protocol_execute(protocol, server->schedule, 0, 0);
        } else {
          /*
           * Do normal and simple re-key.
@@ -1448,7 +1448,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
                              status));
            
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, server->timeout_queue, 0, 300000);
+           silc_protocol_execute(protocol, server->schedule, 0, 300000);
            return;
          }
 
@@ -1493,7 +1493,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
                            status));
          
          protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, server->timeout_queue, 0, 300000);
+         silc_protocol_execute(protocol, server->schedule, 0, 300000);
          return;
        }
       }
@@ -1506,7 +1506,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
        if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_2) {
          /* Error in protocol */
          protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, server->timeout_queue, 0, 300000);
+         silc_protocol_execute(protocol, server->schedule, 0, 300000);
        }
        
        status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer);
@@ -1515,7 +1515,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
                            status));
          
          protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, server->timeout_queue, 0, 300000);
+         silc_protocol_execute(protocol, server->schedule, 0, 300000);
          return;
        }
       }
@@ -1543,7 +1543,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
     if (ctx->packet->type != SILC_PACKET_REKEY_DONE) {
       /* Error in protocol */
       protocol->state = SILC_PROTOCOL_STATE_ERROR;
-      silc_protocol_execute(protocol, server->timeout_queue, 0, 0);
+      silc_protocol_execute(protocol, server->schedule, 0, 0);
     }
 
     /* We received the REKEY_DONE packet and all packets after this is
@@ -1552,7 +1552,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
 
     /* Protocol has ended, call the final callback */
     if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, server->timeout_queue);
+      silc_protocol_execute_final(protocol, server->schedule);
     else
       silc_protocol_free(protocol);
     break;
@@ -1569,7 +1569,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
 
     /* On error the final callback is always called. */
     if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, server->timeout_queue);
+      silc_protocol_execute_final(protocol, server->schedule);
     else
       silc_protocol_free(protocol);
     break;
@@ -1581,7 +1581,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
 
     /* On error the final callback is always called. */
     if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, server->timeout_queue);
+      silc_protocol_execute_final(protocol, server->schedule);
     else
       silc_protocol_free(protocol);
     break;
index 91ee0291b11773c10297347b5c5ccbb296b1e4e1..f9aa6c9ba1f2de82229d7c6ea5fee5843d58cb84 100644 (file)
@@ -270,35 +270,29 @@ int silc_server_init(SilcServer server)
   /* Register protocols */
   silc_server_protocols_register();
 
-  /* Initialize the scheduler. This will register the task queues as well.
-     In SILC we have by default three task queues. One task queue for
-     non-timeout tasks which perform different kind of I/O on file
-     descriptors, timeout task queue for timeout tasks, and, generic
-     non-timeout task queue whose tasks apply to all connections. */
-  server->schedule = silc_schedule_init(&server->io_queue, 
-                                       &server->timeout_queue, 
-                                       &server->generic_queue, 
-                                       SILC_SERVER_MAX_CONNECTIONS);
+  /* Initialize the scheduler. */
+  server->schedule = silc_schedule_init(SILC_SERVER_MAX_CONNECTIONS);
   if (!server->schedule)
     goto err0;
   
-  /* Add the first task to the queue. This is task that is executed by
+  /* Add the first task to the scheduler. This is task that is executed by
      timeout. It expires as soon as the caller calls silc_server_run. This
      task performs authentication protocol and key exchange with our
      primary router. */
-  silc_task_register(server->timeout_queue, sock[0], 
-                    silc_server_connect_to_router,
-                    (void *)server, 0, 1,
-                    SILC_TASK_TIMEOUT,
-                    SILC_TASK_PRI_NORMAL);
+  silc_schedule_task_add(server->schedule, sock[0], 
+                        silc_server_connect_to_router,
+                        (void *)server, 0, 1,
+                        SILC_TASK_TIMEOUT,
+                        SILC_TASK_PRI_NORMAL);
 
-  /* Add listener task to the queue. This task receives new connections to the 
-     server. This task remains on the queue until the end of the program. */
-  silc_task_register(server->io_queue, sock[0],
-                    silc_server_accept_new_connection,
-                    (void *)server, 0, 0, 
-                    SILC_TASK_FD,
-                    SILC_TASK_PRI_NORMAL);
+  /* Add listener task to the scheduler. This task receives new connections
+     to the server. This task remains on the queue until the end of the 
+     program. */
+  silc_schedule_task_add(server->schedule, sock[0],
+                        silc_server_accept_new_connection,
+                        (void *)server, 0, 0, 
+                        SILC_TASK_FD,
+                        SILC_TASK_PRI_NORMAL);
   server->listenning = TRUE;
 
   /* If server connections has been configured then we must be router as
@@ -312,20 +306,20 @@ int silc_server_init(SilcServer server)
   /* Clients local list */
   purge = silc_calloc(1, sizeof(*purge));
   purge->cache = server->local_list->clients;
-  purge->timeout_queue = server->timeout_queue;
-  silc_task_register(purge->timeout_queue, 0, 
-                    silc_idlist_purge,
-                    (void *)purge, 600, 0,
-                    SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+  purge->schedule = server->schedule;
+  silc_schedule_task_add(purge->schedule, 0, 
+                        silc_idlist_purge,
+                        (void *)purge, 600, 0,
+                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
   /* Clients global list */
   purge = silc_calloc(1, sizeof(*purge));
   purge->cache = server->global_list->clients;
-  purge->timeout_queue = server->timeout_queue;
-  silc_task_register(purge->timeout_queue, 0, 
-                    silc_idlist_purge,
-                    (void *)purge, 300, 0,
-                    SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+  purge->schedule = server->schedule;
+  silc_schedule_task_add(purge->schedule, 0, 
+                        silc_idlist_purge,
+                        (void *)purge, 300, 0,
+                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
   SILC_LOG_DEBUG(("Server initialized"));
 
@@ -451,9 +445,6 @@ void silc_server_stop(SilcServer server)
 {
   SILC_LOG_DEBUG(("Stopping server"));
 
-  /* Stop the scheduler, although it might be already stopped. This
-     doesn't hurt anyone. This removes all the tasks and task queues,
-     as well. */
   silc_schedule_stop(server->schedule);
   silc_schedule_uninit(server->schedule);
 
@@ -509,10 +500,10 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
   }
 
   /* Wait one before retrying */
-  silc_task_register(server->timeout_queue, fd, silc_server_connect_router,
-                    context, sconn->retry_timeout, 
-                    server->params->retry_interval_min_usec,
-                    SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+  silc_schedule_task_add(server->schedule, fd, silc_server_connect_router,
+                        context, sconn->retry_timeout, 
+                        server->params->retry_interval_min_usec,
+                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 }
 
 /* Generic routine to use connect to a router. */
@@ -534,10 +525,10 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
                                    sconn->remote_host);
   if (sock < 0) {
     SILC_LOG_ERROR(("Could not connect to router"));
-    silc_task_register(server->timeout_queue, fd, 
-                      silc_server_connect_to_router_retry,
-                      context, 0, 1, SILC_TASK_TIMEOUT, 
-                      SILC_TASK_PRI_NORMAL);
+    silc_schedule_task_add(server->schedule, fd, 
+                          silc_server_connect_to_router_retry,
+                          context, 0, 1, SILC_TASK_TIMEOUT, 
+                          SILC_TASK_PRI_NORMAL);
     return;
   }
 
@@ -575,7 +566,7 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
   /* Register a timeout task that will be executed if the protocol
      is not executed within set limit. */
   proto_ctx->timeout_task = 
-    silc_task_register(server->timeout_queue, sock, 
+    silc_schedule_task_add(server->schedule, sock, 
                       silc_server_timeout_remote,
                       server, server->params->protocol_timeout,
                       server->params->protocol_timeout_usec,
@@ -592,7 +583,7 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
   SILC_REGISTER_CONNECTION_FOR_IO(sock);
   
   /* Run the protocol */
-  silc_protocol_execute(protocol, server->timeout_queue, 0, 0);
+  silc_protocol_execute(protocol, server->schedule, 0, 0);
 }
   
 /* This function connects to our primary router or if we are a router this
@@ -621,7 +612,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
       sconn->remote_host = strdup(server->config->routers->host);
       sconn->remote_port = server->config->routers->port;
 
-      silc_task_register(server->timeout_queue, fd, 
+      silc_schedule_task_add(server->schedule, fd, 
                         silc_server_connect_router,
                         (void *)sconn, 0, 1, SILC_TASK_TIMEOUT, 
                         SILC_TASK_PRI_NORMAL);
@@ -651,7 +642,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
        sconn->remote_host = strdup(ptr->host);
        sconn->remote_port = ptr->port;
 
-       silc_task_register(server->timeout_queue, fd, 
+       silc_schedule_task_add(server->schedule, fd, 
                           silc_server_connect_router,
                           (void *)sconn, 0, 1, SILC_TASK_TIMEOUT, 
                           SILC_TASK_PRI_NORMAL);
@@ -700,7 +691,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
     if (ctx->dest_id)
       silc_free(ctx->dest_id);
     silc_free(ctx);
-    silc_task_unregister_by_callback(server->timeout_queue,
+    silc_schedule_task_del_by_callback(server->schedule,
                                     silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                  "Key exchange failed");
@@ -727,7 +718,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
     if (ctx->dest_id)
       silc_free(ctx->dest_id);
     silc_free(ctx);
-    silc_task_unregister_by_callback(server->timeout_queue,
+    silc_schedule_task_del_by_callback(server->schedule,
                                     silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                  "Key exchange failed");
@@ -769,7 +760,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
     if (ctx->dest_id)
       silc_free(ctx->dest_id);
     silc_free(ctx);
-    silc_task_unregister_by_callback(server->timeout_queue,
+    silc_schedule_task_del_by_callback(server->schedule,
                                     silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                  "Key exchange failed");
@@ -795,14 +786,14 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
      this timelimit the connection will be terminated. Currently
      this is 15 seconds and is hard coded limit (XXX). */
   proto_ctx->timeout_task = 
-    silc_task_register(server->timeout_queue, sock->sock, 
+    silc_schedule_task_add(server->schedule, sock->sock, 
                       silc_server_timeout_remote,
                       (void *)server, 15, 0,
                       SILC_TASK_TIMEOUT,
                       SILC_TASK_PRI_LOW);
 
   /* Run the protocol */
-  silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
+  silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
 }
 
 /* Finalizes the connection to router. Registers a server task to the
@@ -838,7 +829,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   /* Add a task to the queue. This task receives new connections to the 
      server. This task remains on the queue until the end of the program. */
   if (!server->listenning) {
-    silc_task_register(server->io_queue, server->sock, 
+    silc_schedule_task_add(server->schedule, server->sock, 
                       silc_server_accept_new_connection,
                       (void *)server, 0, 0, 
                       SILC_TASK_FD,
@@ -896,12 +887,12 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   hb_context->server = server;
   silc_socket_set_heartbeat(sock, 600, hb_context,
                            silc_server_perform_heartbeat,
-                           server->timeout_queue);
+                           server->schedule);
 
   /* Register re-key timeout */
   idata->rekey->timeout = 3600; /* XXX hardcoded */
   idata->rekey->context = (void *)server;
-  silc_task_register(server->timeout_queue, sock->sock, 
+  silc_schedule_task_add(server->schedule, sock->sock, 
                     silc_server_rekey_callback,
                     (void *)sock, idata->rekey->timeout, 0,
                     SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
@@ -1044,7 +1035,7 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
      now, this is a hard coded limit. After 60 secs the connection will
      be closed if the key exchange protocol has not been started. */
   proto_ctx->timeout_task = 
-    silc_task_register(server->timeout_queue, sock->sock, 
+    silc_schedule_task_add(server->schedule, sock->sock, 
                       silc_server_timeout_remote,
                       context, 60, 0,
                       SILC_TASK_TIMEOUT,
@@ -1092,7 +1083,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
      is accepted further. */
   silc_socket_host_lookup(newsocket, TRUE, 
                          silc_server_accept_new_connection_lookup, context, 
-                         server->timeout_queue);
+                         server->schedule);
 }
 
 /* Second part of accepting new connection. Key exchange protocol has been
@@ -1125,7 +1116,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
     if (ctx->dest_id)
       silc_free(ctx->dest_id);
     silc_free(ctx);
-    silc_task_unregister_by_callback(server->timeout_queue,
+    silc_schedule_task_del_by_callback(server->schedule,
                                     silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                  "Key exchange failed");
@@ -1153,7 +1144,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
     if (ctx->dest_id)
       silc_free(ctx->dest_id);
     silc_free(ctx);
-    silc_task_unregister_by_callback(server->timeout_queue,
+    silc_schedule_task_del_by_callback(server->schedule,
                                     silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                  "Key exchange failed");
@@ -1194,7 +1185,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
      this timelimit the connection will be terminated. Currently
      this is 60 seconds and is hard coded limit (XXX). */
   proto_ctx->timeout_task = 
-    silc_task_register(server->timeout_queue, sock->sock, 
+    silc_schedule_task_add(server->schedule, sock->sock, 
                       silc_server_timeout_remote,
                       (void *)server, 60, 0,
                       SILC_TASK_TIMEOUT,
@@ -1231,7 +1222,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
     silc_free(ctx);
     if (sock)
       sock->protocol = NULL;
-    silc_task_unregister_by_callback(server->timeout_queue,
+    silc_schedule_task_del_by_callback(server->schedule,
                                     silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                  "Authentication failed");
@@ -1357,10 +1348,10 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   hb_context->server = server;
   silc_socket_set_heartbeat(sock, 600, hb_context,
                            silc_server_perform_heartbeat,
-                           server->timeout_queue);
+                           server->schedule);
 
  out:
-  silc_task_unregister_by_callback(server->timeout_queue,
+  silc_schedule_task_del_by_callback(server->schedule,
                                   silc_server_failure_callback);
   silc_protocol_free(protocol);
   if (ctx->packet)
@@ -1467,7 +1458,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
        start re-connecting phase. */
     if (!server->standalone && sock->type == SILC_SOCKET_TYPE_ROUTER && 
        sock == server->router->connection)
-      silc_task_register(server->timeout_queue, 0, 
+      silc_schedule_task_add(server->schedule, 0, 
                         silc_server_connect_to_router,
                         context, 1, 0,
                         SILC_TASK_TIMEOUT,
@@ -1643,7 +1634,7 @@ void silc_server_packet_parse(SilcPacketParserContext *parser_context)
   case SILC_SOCKET_TYPE_UNKNOWN:
   case SILC_SOCKET_TYPE_CLIENT:
     /* Parse the packet with timeout */
-    silc_task_register(server->timeout_queue, sock->sock,
+    silc_schedule_task_add(server->schedule, sock->sock,
                       silc_server_packet_parse_real,
                       (void *)parser_context, 0, 100000,
                       SILC_TASK_TIMEOUT,
@@ -1652,7 +1643,7 @@ void silc_server_packet_parse(SilcPacketParserContext *parser_context)
   case SILC_SOCKET_TYPE_SERVER:
   case SILC_SOCKET_TYPE_ROUTER:
     /* Packets from servers are parsed as soon as possible */
-    silc_task_register(server->timeout_queue, sock->sock,
+    silc_schedule_task_add(server->schedule, sock->sock,
                       silc_server_packet_parse_real,
                       (void *)parser_context, 0, 1,
                       SILC_TASK_TIMEOUT,
@@ -1692,7 +1683,7 @@ void silc_server_packet_parse_type(SilcServer server,
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     if (sock->protocol)
-      silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
+      silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
     break;
 
   case SILC_PACKET_FAILURE:
@@ -1711,7 +1702,7 @@ void silc_server_packet_parse_type(SilcServer server,
       f->sock = sock;
       
       /* We will wait 5 seconds to process this failure packet */
-      silc_task_register(server->timeout_queue, sock->sock,
+      silc_schedule_task_add(server->schedule, sock->sock,
                         silc_server_failure_callback, (void *)f, 5, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
     }
@@ -1830,7 +1821,7 @@ void silc_server_packet_parse_type(SilcServer server,
       proto_ctx->packet = silc_packet_context_dup(packet);
 
       /* Let the protocol handle the packet */
-      silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 100000);
+      silc_protocol_execute(sock->protocol, server->schedule, 0, 100000);
     } else {
       SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
                      "protocol active, packet dropped."));
@@ -1856,7 +1847,7 @@ void silc_server_packet_parse_type(SilcServer server,
        proto_ctx->packet = silc_packet_context_dup(packet);
 
        /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
+       silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
       } else {
        SilcServerKEInternalContext *proto_ctx = 
          (SilcServerKEInternalContext *)sock->protocol->context;
@@ -1872,7 +1863,7 @@ void silc_server_packet_parse_type(SilcServer server,
          break;
 
        /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, server->timeout_queue, 
+       silc_protocol_execute(sock->protocol, server->schedule, 
                              0, 100000);
       }
     } else {
@@ -1900,7 +1891,7 @@ void silc_server_packet_parse_type(SilcServer server,
        proto_ctx->packet = silc_packet_context_dup(packet);
 
        /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
+       silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
       } else {
        SilcServerKEInternalContext *proto_ctx = 
          (SilcServerKEInternalContext *)sock->protocol->context;
@@ -1916,7 +1907,7 @@ void silc_server_packet_parse_type(SilcServer server,
          break;
 
        /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, server->timeout_queue, 
+       silc_protocol_execute(sock->protocol, server->schedule, 
                              0, 100000);
       }
     } else {
@@ -1957,7 +1948,7 @@ void silc_server_packet_parse_type(SilcServer server,
       proto_ctx->packet = silc_packet_context_dup(packet);
 
       /* Let the protocol handle the packet */
-      silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
+      silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
     } else {
       SILC_LOG_ERROR(("Received Connection Auth packet but no authentication "
                      "protocol active, packet dropped."));
@@ -2064,7 +2055,7 @@ void silc_server_packet_parse_type(SilcServer server,
       proto_ctx->packet = silc_packet_context_dup(packet);
 
       /* Let the protocol handle the packet */
-      silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
+      silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
     } else {
       SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
                      "protocol active, packet dropped."));
@@ -2091,7 +2082,7 @@ void silc_server_create_connection(SilcServer server,
   sconn->remote_host = strdup(remote_host);
   sconn->remote_port = port;
 
-  silc_task_register(server->timeout_queue, 0, 
+  silc_schedule_task_add(server->schedule, 0, 
                     silc_server_connect_router,
                     (void *)sconn, 0, 1, SILC_TASK_TIMEOUT, 
                     SILC_TASK_PRI_NORMAL);
@@ -2118,14 +2109,14 @@ void silc_server_close_connection(SilcServer server,
   silc_schedule_unset_listen_fd(server->schedule, sock->sock);
 
   /* Unregister all tasks */
-  silc_task_unregister_by_fd(server->io_queue, sock->sock);
-  silc_task_unregister_by_fd(server->timeout_queue, sock->sock);
+  silc_schedule_task_del_by_fd(server->schedule, sock->sock);
+  silc_schedule_task_del_by_fd(server->schedule, sock->sock);
 
   /* Close the actual connection */
   silc_net_close_connection(sock->sock);
   server->sockets[sock->sock] = NULL;
 
-  silc_task_register(server->timeout_queue, 0, 
+  silc_schedule_task_add(server->schedule, 0, 
                     silc_server_close_connection_final,
                     (void *)sock, 0, 1, SILC_TASK_TIMEOUT, 
                     SILC_TASK_PRI_NORMAL);
@@ -2226,7 +2217,7 @@ void silc_server_free_client_data(SilcServer server,
      into history (for WHOWAS command) for 5 minutes */
   i->server = server;
   i->client = client;
-  silc_task_register(server->timeout_queue, 0, 
+  silc_schedule_task_add(server->schedule, 0, 
                     silc_server_free_client_data_timeout,
                     (void *)i, 300, 0,
                     SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
@@ -2294,9 +2285,9 @@ void silc_server_free_sock_user_data(SilcServer server,
 
   /* If any protocol is active cancel its execution */
   if (sock->protocol) {
-    silc_protocol_cancel(sock->protocol, server->timeout_queue);
+    silc_protocol_cancel(sock->protocol, server->schedule);
     sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
-    silc_protocol_execute_final(sock->protocol, server->timeout_queue);
+    silc_protocol_execute_final(sock->protocol, server->schedule);
     sock->protocol = NULL;
   }
 
@@ -2342,7 +2333,7 @@ static void silc_server_remove_clients_channels(SilcServer server,
        silc_hash_table_del(channels, channel);
 
       if (channel->rekey)
-       silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
+       silc_schedule_task_del_by_context(server->schedule, channel->rekey);
 
       if (!silc_idlist_del_channel(server->local_list, channel))
        silc_idlist_del_channel(server->global_list, channel);
@@ -2370,7 +2361,7 @@ static void silc_server_remove_clients_channels(SilcServer server,
        silc_hash_table_del(channels, channel);
 
       if (channel->rekey)
-       silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
+       silc_schedule_task_del_by_context(server->schedule, channel->rekey);
 
       if (channel->founder_key) {
        /* The founder auth data exists, do not remove the channel entry */
@@ -2673,7 +2664,7 @@ void silc_server_remove_from_channels(SilcServer server,
     if (server->server_type == SILC_ROUTER &&
        silc_hash_table_count(channel->user_list) < 2) {
       if (channel->rekey)
-       silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
+       silc_schedule_task_del_by_context(server->schedule, channel->rekey);
       if (!silc_idlist_del_channel(server->local_list, channel))
        silc_idlist_del_channel(server->global_list, channel);
       server->stat.my_channels--;
@@ -2705,7 +2696,7 @@ void silc_server_remove_from_channels(SilcServer server,
                                           strlen(signoff_message) : 0);
 
       if (channel->rekey)
-       silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
+       silc_schedule_task_del_by_context(server->schedule, channel->rekey);
 
       if (channel->founder_key) {
        /* The founder auth data exists, do not remove the channel entry */
@@ -2789,7 +2780,7 @@ int silc_server_remove_from_one_channel(SilcServer server,
   if (server->server_type == SILC_ROUTER &&
       silc_hash_table_count(channel->user_list) < 2) {
     if (channel->rekey)
-      silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
+      silc_schedule_task_del_by_context(server->schedule, channel->rekey);
     if (!silc_idlist_del_channel(server->local_list, channel))
       silc_idlist_del_channel(server->global_list, channel);
     silc_buffer_free(clidp);
@@ -2821,7 +2812,7 @@ int silc_server_remove_from_one_channel(SilcServer server,
     silc_buffer_free(clidp);
     
     if (channel->rekey)
-      silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
+      silc_schedule_task_del_by_context(server->schedule, channel->rekey);
 
     if (channel->founder_key) {
       /* The founder auth data exists, do not remove the channel entry */
@@ -2891,7 +2882,7 @@ SILC_TASK_CALLBACK(silc_server_timeout_remote)
      final callback so that all the memory is freed. */
   if (sock->protocol) {
     sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
-    silc_protocol_execute_final(sock->protocol, server->timeout_queue);
+    silc_protocol_execute_final(sock->protocol, server->schedule);
     return;
   }
 
@@ -3039,7 +3030,7 @@ SILC_TASK_CALLBACK(silc_server_channel_key_rekey)
   silc_server_create_channel_key(server, rekey->channel, rekey->key_len);
   silc_server_send_channel_key(server, NULL, rekey->channel, FALSE);
 
-  silc_task_register(server->timeout_queue, 0, 
+  silc_schedule_task_add(server->schedule, 0, 
                     silc_server_channel_key_rekey,
                     (void *)rekey, 3600, 0,
                     SILC_TASK_TIMEOUT,
@@ -3108,9 +3099,9 @@ void silc_server_create_channel_key(SilcServer server,
     channel->rekey->channel = channel;
     channel->rekey->key_len = key_len;
 
-    silc_task_unregister_by_callback(server->timeout_queue,
+    silc_schedule_task_del_by_callback(server->schedule,
                                     silc_server_channel_key_rekey);
-    silc_task_register(server->timeout_queue, 0, 
+    silc_schedule_task_add(server->schedule, 0, 
                       silc_server_channel_key_rekey,
                       (void *)channel->rekey, 3600, 0,
                       SILC_TASK_TIMEOUT,
@@ -3213,9 +3204,9 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
     channel->rekey->context = (void *)server;
     channel->rekey->channel = channel;
 
-    silc_task_unregister_by_callback(server->timeout_queue,
+    silc_schedule_task_del_by_callback(server->schedule,
                                     silc_server_channel_key_rekey);
-    silc_task_register(server->timeout_queue, 0, 
+    silc_schedule_task_add(server->schedule, 0, 
                       silc_server_channel_key_rekey,
                       (void *)channel->rekey, 3600, 0,
                       SILC_TASK_TIMEOUT,
@@ -3620,7 +3611,7 @@ SILC_TASK_CALLBACK(silc_server_failure_callback)
 
   if (f->sock->protocol) {
     f->sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
-    silc_protocol_execute(f->sock->protocol, f->server->timeout_queue, 0, 0);
+    silc_protocol_execute(f->sock->protocol, f->server->schedule, 0, 0);
   }
 
   silc_free(f);
@@ -3952,10 +3943,10 @@ SILC_TASK_CALLBACK(silc_server_rekey_callback)
   sock->protocol = protocol;
       
   /* Run the protocol */
-  silc_protocol_execute(protocol, server->timeout_queue, 0, 0);
+  silc_protocol_execute(protocol, server->schedule, 0, 0);
 
   /* Re-register re-key timeout */
-  silc_task_register(server->timeout_queue, sock->sock, 
+  silc_schedule_task_add(server->schedule, sock->sock, 
                     silc_server_rekey_callback,
                     context, idata->rekey->timeout, 0,
                     SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
@@ -3977,7 +3968,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
     /* Error occured during protocol */
-    silc_protocol_cancel(protocol, server->timeout_queue);
+    silc_protocol_cancel(protocol, server->schedule);
     silc_protocol_free(protocol);
     sock->protocol = NULL;
     if (ctx->packet)
index 556f835e6f0c43b681748eee1f2e44efd4d61342..137cf97d8542f13702f82d5567d21ef5c4ed7d09 100644 (file)
@@ -26,7 +26,7 @@
    the object private hence this declaration. */
 typedef struct SilcServerStruct *SilcServer;
 
-#define SILC_SERVER_MAX_CONNECTIONS 10000
+#define SILC_SERVER_MAX_CONNECTIONS 1000
 
 /* General definitions */
 
index 24942e378d23f4158ae4ebee0c6bf9b9bb57a3cd..cc0b00e3c586723fb9dedd7c2b4c31a9e8a723aa 100644 (file)
@@ -95,11 +95,8 @@ struct SilcServerStruct {
   /* Back pointer to the primary router of this server. */
   SilcServerEntry router;
 
-  /* SILC server schduler and task queues */
+  /* SILC server scheduler */
   SilcSchedule schedule;
-  SilcTaskQueue io_queue;
-  SilcTaskQueue timeout_queue;
-  SilcTaskQueue generic_queue;
 
   /* ID lists. */
   SilcIDList local_list;
@@ -166,25 +163,23 @@ typedef struct {
 /* Registers generic task for file descriptor for reading from network and
    writing to network. As being generic task the actual task is allocated 
    only once and after that the same task applies to all registered fd's. */
-#define SILC_REGISTER_CONNECTION_FOR_IO(fd)                            \
-do {                                                                   \
-  SilcTask tmptask = silc_task_register(server->generic_queue, (fd),   \
-                                       silc_server_packet_process,     \
-                                       context, 0, 0,                  \
-                                       SILC_TASK_GENERIC,              \
-                                       SILC_TASK_PRI_NORMAL);          \
-  silc_task_set_iotype(tmptask, SILC_TASK_WRITE);                      \
+#define SILC_REGISTER_CONNECTION_FOR_IO(fd)            \
+do {                                                   \
+  silc_schedule_task_add(server->schedule, (fd),       \
+                        silc_server_packet_process,    \
+                        context, 0, 0,                 \
+                        SILC_TASK_GENERIC,             \
+                        SILC_TASK_PRI_NORMAL);         \
 } while(0)
 
-#define SILC_SET_CONNECTION_FOR_INPUT(s, fd)                           \
-do {                                                                   \
-  silc_schedule_set_listen_fd((s), (fd), (1L << SILC_TASK_READ));      \
+#define SILC_SET_CONNECTION_FOR_INPUT(s, fd)                   \
+do {                                                           \
+  silc_schedule_set_listen_fd((s), (fd), SILC_TASK_READ);      \
 } while(0)
      
-#define SILC_SET_CONNECTION_FOR_OUTPUT(s, fd)                          \
-do {                                                                   \
-  silc_schedule_set_listen_fd((s), (fd), ((1L << SILC_TASK_READ) |     \
-                                    (1L << SILC_TASK_WRITE)));         \
+#define SILC_SET_CONNECTION_FOR_OUTPUT(s, fd)                                \
+do {                                                                         \
+  silc_schedule_set_listen_fd((s), (fd), (SILC_TASK_READ | SILC_TASK_WRITE)); \
 } while(0)
 
 /* Prototypes */
index 4ce05d26e2f11b8827b4f6962d4d5b4c2e238b12..20855d040a400dec80bb67924d81ce809e423c04 100644 (file)
@@ -229,7 +229,6 @@ typedef uint32 * void *;
 #include "silcnet.h"
 #include "silcutil.h"
 #include "silcconfig.h"
-#include "silctask.h"
 #include "silcschedule.h"
 
 /* SILC core library includes */
index 8fa87ad8d7282542836264ec568340c90838df23..45d43517c9fbb60a26f88de87c763d40c13302f3 100644 (file)
@@ -100,9 +100,7 @@ int silc_client_init(SilcClient client)
   silc_client_protocols_register();
 
   /* Initialize the scheduler */
-  client->schedule = silc_schedule_init(&client->io_queue, 
-                                       &client->timeout_queue, 
-                                       &client->generic_queue, 5000);
+  client->schedule = silc_schedule_init(200);
   if (!client->schedule)
     return FALSE;
 
@@ -116,9 +114,6 @@ void silc_client_stop(SilcClient client)
 {
   SILC_LOG_DEBUG(("Stopping client"));
 
-  /* Stop the scheduler, although it might be already stopped. This
-     doesn't hurt anyone. This removes all the tasks and task queues,
-     as well. */
   silc_schedule_stop(client->schedule);
   silc_schedule_uninit(client->schedule);
 
@@ -257,13 +252,12 @@ silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
 
   /* Register task that will receive the async connect and will
      read the result. */
-  ctx->task = silc_task_register(ctx->client->io_queue, sock, 
-                                silc_client_connect_to_server_start,
-                                (void *)ctx, 0, 0, 
-                                SILC_TASK_FD,
-                                SILC_TASK_PRI_NORMAL);
-  silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
-  silc_schedule_set_listen_fd(ctx->client->schedule, sock, ctx->task->iomask);
+  ctx->task = silc_schedule_task_add(ctx->client->schedule, sock, 
+                                    silc_client_connect_to_server_start,
+                                    (void *)ctx, 0, 0, 
+                                    SILC_TASK_FD,
+                                    SILC_TASK_PRI_NORMAL);
+  silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE);
 
   ctx->sock = sock;
 
@@ -364,7 +358,7 @@ int silc_client_start_key_exchange(SilcClient client,
   SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
 
   /* Execute the protocol */
-  silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
+  silc_protocol_execute(protocol, client->schedule, 0, 0);
   return TRUE;
 }
 
@@ -396,7 +390,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
       /* Unregister old connection try */
       silc_schedule_unset_listen_fd(client->schedule, fd);
       silc_net_close_connection(fd);
-      silc_task_unregister(client->io_queue, ctx->task);
+      silc_schedule_task_del(client->schedule, ctx->task);
 
       /* Try again */
       silc_client_connect_to_server_internal(ctx);
@@ -408,7 +402,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
                       ctx->host, strerror(opt));
       silc_schedule_unset_listen_fd(client->schedule, fd);
       silc_net_close_connection(fd);
-      silc_task_unregister(client->io_queue, ctx->task);
+      silc_schedule_task_del(client->schedule, ctx->task);
       silc_free(ctx);
 
       /* Notify application of failure */
@@ -419,7 +413,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
   }
 
   silc_schedule_unset_listen_fd(client->schedule, fd);
-  silc_task_unregister(client->io_queue, ctx->task);
+  silc_schedule_task_del(client->schedule, ctx->task);
   silc_free(ctx);
 
   if (!silc_client_start_key_exchange(client, conn, fd)) {
@@ -501,7 +495,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
                      silc_client_connect_to_server_final);
 
   /* Execute the protocol */
-  silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0);
+  silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
 }
 
 /* Finalizes the connection to the remote SILC server. This is called
@@ -569,7 +563,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
   /* Register re-key timeout */
   conn->rekey->timeout = client->params->rekey_secs;
   conn->rekey->context = (void *)client;
-  silc_task_register(client->timeout_queue, conn->sock->sock, 
+  silc_schedule_task_add(client->schedule, conn->sock->sock, 
                     silc_client_rekey_callback,
                     (void *)conn->sock, conn->rekey->timeout, 0,
                     SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
@@ -786,7 +780,7 @@ void silc_client_packet_parse(SilcPacketParserContext *parser_context)
   SilcClient client = (SilcClient)parser_context->context;
 
   /* Parse the packet */
-  silc_task_register(client->timeout_queue, parser_context->sock->sock, 
+  silc_schedule_task_add(client->schedule, parser_context->sock->sock, 
                     silc_client_packet_parse_real,
                     (void *)parser_context, 0, 1, 
                     SILC_TASK_TIMEOUT,
@@ -817,7 +811,7 @@ void silc_client_packet_parse_type(SilcClient client,
      * success message is for whatever protocol is executing currently.
      */
     if (sock->protocol)
-      silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0);
+      silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
     break;
   case SILC_PACKET_FAILURE:
     /*
@@ -892,7 +886,7 @@ void silc_client_packet_parse_type(SilcClient client,
        break;
 
       /* Let the protocol handle the packet */
-      silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0);
+      silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
     } else {
       SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
                      "protocol active, packet dropped."));
@@ -914,7 +908,7 @@ void silc_client_packet_parse_type(SilcClient client,
        proto_ctx->packet = silc_packet_context_dup(packet);
 
        /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0);
+       silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
       } else {
        SilcClientKEInternalContext *proto_ctx = 
          (SilcClientKEInternalContext *)sock->protocol->context;
@@ -930,7 +924,7 @@ void silc_client_packet_parse_type(SilcClient client,
          break;
        
        /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0);
+       silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
       }
     } else {
       SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
@@ -952,7 +946,7 @@ void silc_client_packet_parse_type(SilcClient client,
        proto_ctx->packet = silc_packet_context_dup(packet);
 
        /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0);
+       silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
       } else {
        SilcClientKEInternalContext *proto_ctx = 
          (SilcClientKEInternalContext *)sock->protocol->context;
@@ -968,7 +962,7 @@ void silc_client_packet_parse_type(SilcClient client,
          break;
        
        /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0);
+       silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
       }
     } else {
       SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
@@ -1033,10 +1027,10 @@ void silc_client_packet_parse_type(SilcClient client,
 
       /* Let the protocol handle the packet */
       if (proto_ctx->responder == FALSE)
-       silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0);
+       silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
       else
        /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, client->timeout_queue, 
+       silc_protocol_execute(sock->protocol, client->schedule, 
                              0, 100000);
     } else {
       SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
@@ -1168,8 +1162,8 @@ void silc_client_close_connection(SilcClient client,
   silc_schedule_unset_listen_fd(client->schedule, sock->sock);
 
   /* Unregister all tasks */
-  silc_task_unregister_by_fd(client->io_queue, sock->sock);
-  silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
+  silc_schedule_task_del_by_fd(client->schedule, sock->sock);
+  silc_schedule_task_del_by_fd(client->schedule, sock->sock);
 
   /* Close the actual connection */
   silc_net_close_connection(sock->sock);
@@ -1181,14 +1175,14 @@ void silc_client_close_connection(SilcClient client,
        sock->protocol->protocol->type == 
        SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
       sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
-      silc_protocol_execute_final(sock->protocol, client->timeout_queue);
+      silc_protocol_execute_final(sock->protocol, client->schedule);
       sock->protocol = NULL;
       /* The application will recall this function with these protocols
         (the ops->connect client operation). */
       return;
     } else {
       sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
-      silc_protocol_execute_final(sock->protocol, client->timeout_queue);
+      silc_protocol_execute_final(sock->protocol, client->schedule);
       sock->protocol = NULL;
     }
   }
@@ -1483,10 +1477,10 @@ SILC_TASK_CALLBACK(silc_client_rekey_callback)
   sock->protocol = protocol;
       
   /* Run the protocol */
-  silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
+  silc_protocol_execute(protocol, client->schedule, 0, 0);
 
   /* Re-register re-key timeout */
-  silc_task_register(client->timeout_queue, sock->sock, 
+  silc_schedule_task_add(client->schedule, sock->sock, 
                     silc_client_rekey_callback,
                     context, conn->rekey->timeout, 0,
                     SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
@@ -1508,7 +1502,7 @@ SILC_TASK_CALLBACK(silc_client_rekey_final)
   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
     /* Error occured during protocol */
-    silc_protocol_cancel(protocol, client->timeout_queue);
+    silc_protocol_cancel(protocol, client->schedule);
     silc_protocol_free(protocol);
     sock->protocol = NULL;
     if (ctx->packet)
index f886e3d374fe5064e67c5661f0d570b46acb3876..89195d053d4372157a05e9091eff51197dbdbb88 100644 (file)
@@ -161,11 +161,8 @@ struct SilcClientStruct {
   /* Client Parameters */
   SilcClientParams *params;
 
-  /* SILC client scheduler and task queues */
+  /* SILC client scheduler */
   SilcSchedule schedule;
-  SilcTaskQueue io_queue;
-  SilcTaskQueue timeout_queue;
-  SilcTaskQueue generic_queue;
 
   /* Table of connections in client. All the connection data is saved here. */
   SilcClientConnection *conns;
@@ -199,25 +196,24 @@ struct SilcClientStruct {
 /* Registers generic task for file descriptor for reading from network and
    writing to network. As being generic task the actual task is allocated 
    only once and after that the same task applies to all registered fd's. */
-#define SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd)                     \
-do {                                                                   \
-  SilcTask tmptask = silc_task_register(client->generic_queue, (fd),   \
-                                       silc_client_packet_process,     \
-                                       context, 0, 0,                  \
-                                       SILC_TASK_GENERIC,              \
-                                       SILC_TASK_PRI_NORMAL);          \
-  silc_task_set_iotype(tmptask, SILC_TASK_WRITE);                      \
+#define SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd)     \
+do {                                                   \
+  silc_schedule_task_add(client->schedule, (fd),       \
+                        silc_client_packet_process,    \
+                        context, 0, 0,                 \
+                        SILC_TASK_GENERIC,             \
+                        SILC_TASK_PRI_NORMAL);         \
 } while(0)
 
-#define SILC_CLIENT_SET_CONNECTION_FOR_INPUT(s, fd)                    \
-do {                                                                   \
-  silc_schedule_set_listen_fd((s), (fd), (1L << SILC_TASK_READ));      \
+#define SILC_CLIENT_SET_CONNECTION_FOR_INPUT(s, fd)            \
+do {                                                           \
+  silc_schedule_set_listen_fd((s), (fd), SILC_TASK_READ);      \
 } while(0)
      
-#define SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(s, fd)                   \
-do {                                                                   \
-  silc_schedule_set_listen_fd((s), (fd), ((1L << SILC_TASK_READ) |     \
-                                    (1L << SILC_TASK_WRITE)));         \
+#define SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(s, fd)           \
+do {                                                           \
+  silc_schedule_set_listen_fd((s), (fd), (SILC_TASK_READ |     \
+                                         SILC_TASK_WRITE));    \
 } while(0)
 
 /* Finds socket connection object by file descriptor */
index 41c6edff3091daadfba0ceda553133799988e920..c68a432fd3b3405f48faed5b7756ca4f001938b1 100644 (file)
@@ -120,14 +120,14 @@ SILC_TASK_CALLBACK(silc_client_key_agreement_final)
     silc_ske_free(ctx->ske);
   if (ctx->dest_id)
     silc_free(ctx->dest_id);
-  silc_task_unregister_by_fd(client->io_queue, ke->fd);
+  silc_schedule_task_del_by_fd(client->schedule, ke->fd);
   silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
   silc_net_close_connection(ke->fd);
   if (ke->timeout)
-    silc_task_unregister(client->timeout_queue, ke->timeout);
+    silc_schedule_task_del(client->schedule, ke->timeout);
   silc_client_del_socket(ke->client, ke->sock);
 
-  silc_task_register(client->timeout_queue, 0, 
+  silc_schedule_task_add(client->schedule, 0, 
                     silc_client_key_agreement_close,
                     (void *)ke, 0, 1, 
                     SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
@@ -158,11 +158,11 @@ SILC_TASK_CALLBACK(silc_client_process_key_agreement)
     ke->client_entry->ke = NULL;
     ke->completion(ke->client, ke->conn, ke->client_entry, 
                   SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
-    silc_task_unregister_by_fd(client->io_queue, ke->fd);
+    silc_schedule_task_del_by_fd(client->schedule, ke->fd);
     silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
     silc_net_close_connection(ke->fd);
     if (ke->timeout)
-      silc_task_unregister(client->timeout_queue, ke->timeout);
+      silc_schedule_task_del(client->schedule, ke->timeout);
     silc_free(ke);
     return;
   }
@@ -185,11 +185,11 @@ SILC_TASK_CALLBACK(silc_client_process_key_agreement)
     ke->client_entry->ke = NULL;
     ke->completion(ke->client, ke->conn, ke->client_entry, 
                   SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
-    silc_task_unregister_by_fd(client->io_queue, ke->fd);
+    silc_schedule_task_del_by_fd(client->schedule, ke->fd);
     silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
     silc_net_close_connection(ke->fd);
     if (ke->timeout)
-      silc_task_unregister(client->timeout_queue, ke->timeout);
+      silc_schedule_task_del(client->schedule, ke->timeout);
     silc_free(ke);
     return;
   }
@@ -248,7 +248,7 @@ SILC_TASK_CALLBACK(silc_client_key_agreement_timeout)
     silc_ske_free(ke->proto_ctx->ske);
   ke->client_entry->ke = NULL;
   if (ke->fd)
-    silc_task_unregister_by_fd(ke->client->io_queue, ke->fd);
+    silc_schedule_task_del_by_fd(ke->client->schedule, ke->fd);
   silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
   silc_net_close_connection(ke->fd);
   silc_free(ke);
@@ -331,18 +331,18 @@ void silc_client_send_key_agreement(SilcClient client,
     ke->completion = completion;
     ke->context = context;
 
-    /* Add listener task to the queue. This task receives the key 
+    /* Add listener task to the scheduler. This task receives the key 
        negotiations. */
-    silc_task_register(client->io_queue, ke->fd,
-                      silc_client_process_key_agreement,
-                      (void *)ke, 0, 0, 
-                      SILC_TASK_FD,
-                      SILC_TASK_PRI_NORMAL);
+    silc_schedule_task_add(client->schedule, ke->fd,
+                          silc_client_process_key_agreement,
+                          (void *)ke, 0, 0, 
+                          SILC_TASK_FD,
+                          SILC_TASK_PRI_NORMAL);
 
     /* Register a timeout task that will be executed if the connector
        will not start the key exchange protocol within the specified 
        timeout. */
-    ke->timeout = silc_task_register(client->timeout_queue, 0, 
+    ke->timeout = silc_schedule_task_add(client->schedule, 0, 
                                     silc_client_key_agreement_timeout,
                                     (void *)ke, timeout_secs, 0, 
                                     SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
@@ -372,13 +372,12 @@ silc_client_connect_to_client_internal(SilcClientInternalConnectContext *ctx)
 
   /* Register task that will receive the async connect and will
      read the result. */
-  ctx->task = silc_task_register(ctx->client->io_queue, sock, 
+  ctx->task = silc_schedule_task_add(ctx->client->schedule, sock, 
                                 silc_client_perform_key_agreement_start,
                                 (void *)ctx, 0, 0, 
                                 SILC_TASK_FD,
                                 SILC_TASK_PRI_NORMAL);
-  silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
-  silc_schedule_set_listen_fd(ctx->client->schedule, sock, ctx->task->iomask);
+  silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE);
 
   ctx->sock = sock;
 
@@ -438,7 +437,7 @@ SILC_TASK_CALLBACK(silc_client_perform_key_agreement_start)
       /* Unregister old connection try */
       silc_schedule_unset_listen_fd(client->schedule, fd);
       silc_net_close_connection(fd);
-      silc_task_unregister(client->io_queue, ctx->task);
+      silc_schedule_task_del(client->schedule, ctx->task);
 
       /* Try again */
       silc_client_connect_to_client_internal(ctx);
@@ -450,7 +449,7 @@ SILC_TASK_CALLBACK(silc_client_perform_key_agreement_start)
                       ctx->host, strerror(opt));
       silc_schedule_unset_listen_fd(client->schedule, fd);
       silc_net_close_connection(fd);
-      silc_task_unregister(client->io_queue, ctx->task);
+      silc_schedule_task_del(client->schedule, ctx->task);
       silc_free(ctx->host);
       silc_free(ctx);
 
@@ -463,7 +462,7 @@ SILC_TASK_CALLBACK(silc_client_perform_key_agreement_start)
   }
 
   silc_schedule_unset_listen_fd(client->schedule, fd);
-  silc_task_unregister(client->io_queue, ctx->task);
+  silc_schedule_task_del(client->schedule, ctx->task);
 
   ke->fd = fd;
 
@@ -590,7 +589,7 @@ void silc_client_perform_key_agreement_fd(SilcClient client,
   SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
 
   /* Execute the protocol */
-  silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
+  silc_protocol_execute(protocol, client->schedule, 0, 0);
 }
 
 /* This function can be called to unbind the hostname and the port for
@@ -612,9 +611,9 @@ void silc_client_abort_key_agreement(SilcClient client,
       silc_socket_free(client_entry->ke->sock);
     }
     client_entry->ke = NULL;
-    silc_task_unregister_by_fd(client->io_queue, client_entry->ke->fd);
+    silc_schedule_task_del_by_fd(client->schedule, client_entry->ke->fd);
     if (client_entry->ke->timeout)
-      silc_task_unregister(client->timeout_queue, 
+      silc_schedule_task_del(client->schedule, 
                           client_entry->ke->timeout);
     silc_free(client_entry->ke);
   }
index f9fc1f805b2e38fcc765ce47f1fd66750f610dda..d74faf3db569c5784a5abf4d37fb41849b4b25ac 100644 (file)
@@ -716,9 +716,9 @@ SILC_CLIENT_CMD_FUNC(quit)
   q->conn = cmd->conn;
 
   /* We quit the connection with little timeout */
-  silc_task_register(cmd->client->timeout_queue, cmd->conn->sock->sock,
-                    silc_client_command_quit_cb, (void *)q,
-                    1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+  silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
+                        silc_client_command_quit_cb, (void *)q,
+                        1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 
   /* Notify application */
   COMMAND;
index ecfa193cd729231badf5c00e86f387a678daf644..5ba28db6e17e507543753da37c5ec0e8539636e6 100644 (file)
@@ -244,7 +244,7 @@ static void silc_client_protocol_ke_continue(SilcSKE ske,
     }
     
     protocol->state = SILC_PROTOCOL_STATE_ERROR;
-    silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
+    silc_protocol_execute(protocol, client->schedule, 0, 0);
     return;
   }
 
@@ -264,7 +264,7 @@ static void silc_client_protocol_ke_continue(SilcSKE ske,
      function. */
   if (ctx->responder == TRUE) {
     protocol->state++;
-    silc_protocol_execute(protocol, client->timeout_queue, 0, 100000);
+    silc_protocol_execute(protocol, client->schedule, 0, 100000);
   }
 }
 
@@ -336,14 +336,14 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
                        status));
 
        protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
+       silc_protocol_execute(protocol, client->schedule, 0, 0);
        return;
       }
 
       /* Advance protocol state and call the next state if we are responder */
       protocol->state++;
       if (ctx->responder == TRUE)
-       silc_protocol_execute(protocol, client->timeout_queue, 0, 100000);
+       silc_protocol_execute(protocol, client->schedule, 0, 100000);
     }
     break;
   case 2:
@@ -371,14 +371,14 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
                        status));
 
        protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
+       silc_protocol_execute(protocol, client->schedule, 0, 0);
        return;
       }
 
       /* Advance protocol state and call next state if we are initiator */
       protocol->state++;
       if (ctx->responder == FALSE)
-       silc_protocol_execute(protocol, client->timeout_queue, 0, 100000);
+       silc_protocol_execute(protocol, client->schedule, 0, 100000);
     }
     break;
   case 3:
@@ -413,7 +413,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
                        status));
 
        protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
+       silc_protocol_execute(protocol, client->schedule, 0, 0);
        return;
       }
     }
@@ -455,7 +455,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
                           ctx->sock->hostname);
         }
        protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
+       silc_protocol_execute(protocol, client->schedule, 0, 0);
        return;
       }
     }
@@ -476,7 +476,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
                                             keymat);
       if (status != SILC_SKE_STATUS_OK) {
        protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, client->timeout_queue, 0, 300000);
+       silc_protocol_execute(protocol, client->schedule, 0, 300000);
        silc_ske_free_key_material(keymat);
        return;
       }
@@ -491,11 +491,11 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
         This was the timeout task to be executed if the protocol is
         not completed fast enough. */
       if (ctx->timeout_task)
-       silc_task_unregister(client->timeout_queue, ctx->timeout_task);
+       silc_schedule_task_del(client->schedule, ctx->timeout_task);
 
       /* Protocol has ended, call the final callback */
       if (protocol->final_callback)
-       silc_protocol_execute_final(protocol, client->timeout_queue);
+       silc_protocol_execute_final(protocol, client->schedule);
       else
        silc_protocol_free(protocol);
     }
@@ -511,7 +511,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
 
     /* On error the final callback is always called. */
     if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, client->timeout_queue);
+      silc_protocol_execute_final(protocol, client->schedule);
     else
       silc_protocol_free(protocol);
     break;
@@ -525,11 +525,11 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
        This was the timeout task to be executed if the protocol is
        not completed fast enough. */
     if (ctx->timeout_task)
-      silc_task_unregister(client->timeout_queue, ctx->timeout_task);
+      silc_schedule_task_del(client->schedule, ctx->timeout_task);
 
     /* On error the final callback is always called. */
     if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, client->timeout_queue);
+      silc_protocol_execute_final(protocol, client->schedule);
     else
       silc_protocol_free(protocol);
     break;
@@ -702,7 +702,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
 
       /* Protocol has ended, call the final callback */
       if (protocol->final_callback)
-       silc_protocol_execute_final(protocol, client->timeout_queue);
+       silc_protocol_execute_final(protocol, client->schedule);
       else
        silc_protocol_free(protocol);
     }
@@ -724,7 +724,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
 
       /* On error the final callback is always called. */
       if (protocol->final_callback)
-       silc_protocol_execute_final(protocol, client->timeout_queue);
+       silc_protocol_execute_final(protocol, client->schedule);
       else
        silc_protocol_free(protocol);
     }
@@ -736,7 +736,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
 
     /* On error the final callback is always called. */
     if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, client->timeout_queue);
+      silc_protocol_execute_final(protocol, client->schedule);
     else
       silc_protocol_free(protocol);
     break;
@@ -926,7 +926,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
          if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_1) {
            /* Error in protocol */
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, client->timeout_queue, 0, 300000);
+           silc_protocol_execute(protocol, client->schedule, 0, 300000);
          }
 
          ctx->ske = silc_ske_alloc();
@@ -946,13 +946,13 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
                              status));
            
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, client->timeout_queue, 0, 300000);
+           silc_protocol_execute(protocol, client->schedule, 0, 300000);
            return;
          }
 
          /* Advance the protocol state */
          protocol->state++;
-         silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
+         silc_protocol_execute(protocol, client->schedule, 0, 0);
        } else {
          /*
           * Do normal and simple re-key.
@@ -1003,7 +1003,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
                              status));
            
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, client->timeout_queue, 0, 300000);
+           silc_protocol_execute(protocol, client->schedule, 0, 300000);
            return;
          }
 
@@ -1050,7 +1050,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
                              status));
            
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, client->timeout_queue, 0, 300000);
+           silc_protocol_execute(protocol, client->schedule, 0, 300000);
            return;
          }
       }
@@ -1063,7 +1063,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
        if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_2) {
          /* Error in protocol */
          protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, client->timeout_queue, 0, 300000);
+         silc_protocol_execute(protocol, client->schedule, 0, 300000);
        }
        
        status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer);
@@ -1072,7 +1072,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
                            status));
          
          protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, client->timeout_queue, 0, 300000);
+         silc_protocol_execute(protocol, client->schedule, 0, 300000);
          return;
        }
       }
@@ -1100,7 +1100,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
     if (ctx->packet->type != SILC_PACKET_REKEY_DONE) {
       /* Error in protocol */
       protocol->state = SILC_PROTOCOL_STATE_ERROR;
-      silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
+      silc_protocol_execute(protocol, client->schedule, 0, 0);
     }
 
     /* We received the REKEY_DONE packet and all packets after this is
@@ -1109,7 +1109,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
 
     /* Protocol has ended, call the final callback */
     if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, client->timeout_queue);
+      silc_protocol_execute_final(protocol, client->schedule);
     else
       silc_protocol_free(protocol);
     break;
@@ -1126,7 +1126,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
 
     /* On error the final callback is always called. */
     if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, client->timeout_queue);
+      silc_protocol_execute_final(protocol, client->schedule);
     else
       silc_protocol_free(protocol);
     break;
@@ -1138,7 +1138,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
 
     /* On error the final callback is always called. */
     if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, client->timeout_queue);
+      silc_protocol_execute_final(protocol, client->schedule);
     else
       silc_protocol_free(protocol);
     break;
index 9f091e6a5b6b579276a0c098035e32ec7ac66ac5..9c91d845bdc148002697683367c2f65e356e6e02 100644 (file)
@@ -114,30 +114,29 @@ void silc_protocol_free(SilcProtocol protocol)
 /* Executes next state of the protocol. The state must be set before
    calling this function. */
 
-void silc_protocol_execute(SilcProtocol protocol, void *timeout_queue,
+void silc_protocol_execute(SilcProtocol protocol, SilcSchedule schedule,
                           long secs, long usecs)
 {
   if (secs + usecs) 
-    silc_task_register(timeout_queue, 0, 
-                      protocol->protocol->callback, (void *)protocol, 
-                      secs, usecs, 
-                      SILC_TASK_TIMEOUT,
-                      SILC_TASK_PRI_NORMAL);
+    silc_schedule_task_add(schedule, 0, 
+                          protocol->protocol->callback, (void *)protocol, 
+                          secs, usecs, 
+                          SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_NORMAL);
   else
-    protocol->protocol->callback(timeout_queue, 0, (void *)protocol, 0);
+    protocol->protocol->callback(schedule, 0, 0, (void *)protocol);
 }
 
 /* Executes the final callback of the protocol. */
 
-void silc_protocol_execute_final(SilcProtocol protocol, void *timeout_queue)
+void silc_protocol_execute_final(SilcProtocol protocol, SilcSchedule schedule)
 {
-  protocol->final_callback(timeout_queue, 0, (void *)protocol, 0);
+  protocol->final_callback(schedule, 0, 0, (void *)protocol);
 }
 
 /* Cancels the execution of the next state of the protocol. */
 
-void silc_protocol_cancel(SilcProtocol protocol, void *timeout_queue)
+void silc_protocol_cancel(SilcProtocol protocol, SilcSchedule schedule)
 {
-  silc_task_unregister_by_callback(timeout_queue, 
-                                  protocol->protocol->callback);
+  silc_schedule_task_del_by_callback(schedule, protocol->protocol->callback);
 }
index 197307c225306f0db706d018fd7db7711710c827..e7bb36576bbfae33abcc3f891d6c5615d9f516d2 100644 (file)
@@ -297,7 +297,7 @@ void silc_protocol_free(SilcProtocol protocol);
  *
  * SYNOPSIS
  *
- *    void silc_protocol_execute(SilcProtocol protocol, void *timeout_queue,
+ *    void silc_protocol_execute(SilcProtocol protocol, SilcSchedule schedule,
  *                               long secs, long usecs);
  *
  * DESCRIPTION
@@ -305,13 +305,13 @@ void silc_protocol_free(SilcProtocol protocol);
  *    Executes the protocol. This calls the state that has been set.
  *    The state must be set before calling this function. This is then
  *    also used to call always the next state after changing the state
- *    of the protocol. The `timeout_queue' is a timeout task queue from
- *    the application. It is passed to the protocol callback functions.
- *    The `secs' and `usecs' are the timeout before the protocol is
- *    executed. If both zero the protocol is executed immediately.
+ *    of the protocol. The `schedule' is the application's scheduler.
+ *    It is passed to the protocol callback functions. The `secs' and 
+ *    `usecs' are the timeout before the protocol is executed. If both 
+ *    zero the protocol is executed immediately.
  *
  ***/
-void silc_protocol_execute(SilcProtocol protocol, void *timeout_queue,
+void silc_protocol_execute(SilcProtocol protocol, SilcSchedule schedule,
                           long secs, long usecs);
 
 /****f* silccore/SilcProtocolAPI/silc_protocol_execute_final
@@ -319,23 +319,23 @@ void silc_protocol_execute(SilcProtocol protocol, void *timeout_queue,
  * SYNOPSIS
  *
  *    void 
- *    silc_protocol_execute_final(SilcProtocol protocol, void *timeout_queue);
+ *    silc_protocol_execute_final(SilcProtocol protocol, 
+ *                               SilcSchedule schedule);
  *
  * DESCRIPTION
  *
- *    Executes the final callback for the protocol. The `timeout_queue' is
- *    a timeout task queue from the application. It is passed to the
- *    protocol callback functions. The final callback is executed 
- *    immediately.
+ *    Executes the final callback for the protocol. The `schedule' is
+ *    the application's scheduler.. It is passed to the protocol callback
+ *    functions. The final callback is executed immediately.
  *
  ***/
-void silc_protocol_execute_final(SilcProtocol protocol, void *timeout_queue);
+void silc_protocol_execute_final(SilcProtocol protocol, SilcSchedule schedule);
 
 /****f* silccore/SilcProtocolAPI/silc_protocol_cancel
  *
  * SYNOPSIS
  *
- *    void silc_protocol_cancel(SilcProtocol protocol, void *timeout_queue);
+ *    void silc_protocol_cancel(SilcProtocol protocol, SilcSchedule schedule);
  *
  * DESCRIPTION
  *
@@ -345,6 +345,6 @@ void silc_protocol_execute_final(SilcProtocol protocol, void *timeout_queue);
  *    has elapsed the protocol callback won't be called.
  *
  ***/
-void silc_protocol_cancel(SilcProtocol protocol, void *timeout_queue);
+void silc_protocol_cancel(SilcProtocol protocol, SilcSchedule schedule);
 
 #endif
index 161f04712922c77a157843affe375efab809d323..e016899336838b3b75dcc5a9e46c770df6605859 100644 (file)
@@ -32,7 +32,6 @@ libsilcutil_a_SOURCES = \
        silclog.c \
        silcmemory.c \
        silcnet.c \
-       silctask.c \
        silcschedule.c \
        silcutil.c \
        silchashtable.c \
@@ -50,7 +49,6 @@ include_HEADERS =     \
        silcnet.h       \
        silcschedule.h  \
        silcsockconn.h  \
-       silctask.h      \
        silcthread.h    \
        silcutil.h
 
index 8146c1de0bd533747c4ee459fadd33e109a138c5..ad43f982a3b42b25f7ad13317beb82bcccd090f7 100644 (file)
 /* $Id$ */
 
 #include "silcincludes.h"
+#include "silcschedule_i.h"
 
-/* Routine to remove the task. Implemented in silctask.c. */
-int silc_task_remove(SilcTaskQueue queue, SilcTask task);
-
-/* Routine to compare task timeouts. Implemented in silctask.c. */
-int silc_task_timeout_compare(struct timeval *smaller, 
-                             struct timeval *bigger);
+/* Forward declarations */
+typedef struct SilcTaskQueueStruct *SilcTaskQueue;
 
 /* System specific routines. Implemented under unix/ and win32/. */
 
-/* System specific select(). */
-int silc_select(int n, fd_set *readfds, fd_set *writefds,
-               fd_set *exceptfds, struct timeval *timeout);
+/* System specific select(). Returns same values as normal select(). */
+int silc_select(SilcScheduleFd fds, uint32 fds_count, struct timeval *timeout);
 
 /* Initializes the wakeup of the scheduler. In multi-threaded environment
    the scheduler needs to be wakenup when tasks are added or removed from
@@ -40,7 +36,7 @@ int silc_select(int n, fd_set *readfds, fd_set *writefds,
    Any tasks that needs to be registered must be registered to the `queue'.
    It is guaranteed that the scheduler will automatically free any
    registered tasks in this queue. This is system specific routine. */
-void *silc_schedule_wakeup_init(void *queue);
+void *silc_schedule_wakeup_init(SilcSchedule schedule);
 
 /* Uninitializes the system specific wakeup. */
 void silc_schedule_wakeup_uninit(void *context);
@@ -48,16 +44,55 @@ void silc_schedule_wakeup_uninit(void *context);
 /* Wakes up the scheduler. This is platform specific routine */
 void silc_schedule_wakeup_internal(void *context);
 
-/* Structure holding list of file descriptors, scheduler is supposed to
-   be listenning. The max_fd field is the maximum number of possible file
-   descriptors in the list. This value is set at the initialization
-   of the scheduler and it usually is the maximum number of connections 
-   allowed. */
-typedef struct {
-  int *fd;
-  uint32 last_fd;
-  uint32 max_fd;
-} SilcScheduleFdList;
+
+/* Internal task management routines. */
+
+static void silc_task_queue_alloc(SilcTaskQueue *queue);
+static void silc_task_queue_free(SilcTaskQueue queue);
+static SilcTask silc_task_find(SilcTaskQueue queue, uint32 fd);
+static SilcTask silc_task_add(SilcTaskQueue queue, SilcTask newtask, 
+                             SilcTaskPriority priority);
+static SilcTask silc_task_get_first(SilcTaskQueue queue, SilcTask first);
+static SilcTask silc_task_add_timeout(SilcTaskQueue queue, SilcTask newtask,
+                                     SilcTaskPriority priority);
+static int silc_schedule_task_remove(SilcTaskQueue queue, SilcTask task);
+static int silc_schedule_task_timeout_compare(struct timeval *smaller, 
+                                             struct timeval *bigger);
+static void silc_task_del_by_context(SilcTaskQueue queue, void *context);
+static void silc_task_del_by_callback(SilcTaskQueue queue,
+                                     SilcTaskCallback callback);
+static void silc_task_del_by_fd(SilcTaskQueue queue, uint32 fd);
+
+/* Returns the task queue by task type */
+#define SILC_SCHEDULE_GET_QUEUE(type)                                  \
+  (type == SILC_TASK_FD ? schedule->fd_queue :                         \
+   type == SILC_TASK_TIMEOUT ? schedule->timeout_queue :               \
+   schedule->generic_queue)
+
+/* SILC Task object. Represents one task in the scheduler. */
+struct SilcTaskStruct {
+  uint32 fd;
+  struct timeval timeout;
+  SilcTaskCallback callback;
+  void *context;
+  bool valid;
+  SilcTaskPriority priority;
+  SilcTaskType type;
+
+  /* Pointers forming doubly linked circular list */
+  struct SilcTaskStruct *next;
+  struct SilcTaskStruct *prev;
+};
+
+/* SILC Task Queue object. The queue holds all the tasks in the scheduler.
+   There are always three task queues in the scheduler. One for non-timeout
+   tasks (fd tasks performing tasks over specified file descriptor), 
+   one for timeout tasks and one for generic tasks. */
+struct SilcTaskQueueStruct {
+  SilcTask task;               /* Pointer to all tasks */
+  struct timeval timeout;      /* Current timeout */
+  SILC_MUTEX_DEFINE(lock);     /* Queue's lock */
+};
 
 /* 
    SILC Scheduler structure.
@@ -91,17 +126,24 @@ typedef struct {
        to those that have specificly registered a non-timeout task. This hook
        is also initialized in silc_schedule_init function.
 
-   SilcScheduleFdList fd_list
+   SilcScheduleFd fd_list
 
        List of file descriptors the scheduler is supposed to be listenning.
        This is updated internally.
 
+   uint32 max_fd
+   uint32 last_fd
+
+       Size of the fd_list list. There can be `max_fd' many tasks in
+       the scheduler at once. The `last_fd' is the last valid entry
+       in the fd_list.
+
    struct timeval *timeout;
 
        Pointer to the schedules next timeout. Value of this timeout is
        automatically updated in the silc_schedule function.
 
-   int valid
+   bool valid
 
        Marks validity of the scheduler. This is a boolean value. When this
        is false the scheduler is terminated and the program will end. This
@@ -114,83 +156,61 @@ typedef struct {
        File descriptor sets for select(). These are automatically managed
        by the scheduler and should not be touched otherwise.
 
-   int max_fd
-
-       Number of maximum file descriptors for select(). This, as well, is
-       managed automatically by the scheduler and should be considered to 
-       be read-only field otherwise.
-
    void *wakeup
 
        System specific wakeup context. On multi-threaded environments the
        scheduler needs to be wakenup (in the thread) when tasks are added
        or removed. This is initialized by silc_schedule_wakeup_init.
 
+   SILC_MUTEX_DEFINE(lock)
+  
+       Scheduler lock.
+
 */
 struct SilcScheduleStruct {
   SilcTaskQueue fd_queue;
   SilcTaskQueue timeout_queue;
   SilcTaskQueue generic_queue;
-  SilcScheduleFdList fd_list;
+  SilcScheduleFd fd_list;
+  uint32 max_fd;
+  uint32 last_fd;
   struct timeval *timeout;
   bool valid;
-  fd_set in;
-  fd_set out;
-  int max_fd;
   void *wakeup;
   SILC_MUTEX_DEFINE(lock);
   bool is_locked;
 };
 
-/* Initializes the scheduler. Sets the non-timeout task queue hook and
-   the timeout task queue hook. This must be called before the scheduler
-   is able to work. This will allocate the queue pointers if they are
-   not allocated. Returns the scheduler context that must be freed by
-   the silc_schedule_uninit function. */
+/* Initializes the scheduler. This returns the scheduler context that
+   is given as arugment usually to all silc_schedule_* functions.
+   The `max_tasks' indicates the number of maximum tasks that the
+   scheduler can handle. */
 
-SilcSchedule silc_schedule_init(SilcTaskQueue *fd_queue,
-                               SilcTaskQueue *timeout_queue,
-                               SilcTaskQueue *generic_queue,
-                               int max_fd)
+SilcSchedule silc_schedule_init(int max_tasks)
 {
   SilcSchedule schedule;
-  int i;
 
   SILC_LOG_DEBUG(("Initializing scheduler"));
 
   schedule = silc_calloc(1, sizeof(*schedule));
 
-  /* Register the task queues if they are not registered already. In SILC
-     we have by default three task queues. One task queue for non-timeout
-     tasks which perform different kind of I/O on file descriptors, timeout
-     task queue for timeout tasks, and, generic non-timeout task queue whose
-     tasks apply to all connections. */
-  if (!*fd_queue)
-    silc_task_queue_alloc(schedule, fd_queue, TRUE);
-  if (!*timeout_queue)
-    silc_task_queue_alloc(schedule, timeout_queue, TRUE);
-  if (!*generic_queue)
-    silc_task_queue_alloc(schedule, generic_queue, TRUE);
+  /* Allocate three task queues, one for file descriptor based tasks,
+     one for timeout tasks and one for generic tasks. */
+  silc_task_queue_alloc(&schedule->fd_queue);
+  silc_task_queue_alloc(&schedule->timeout_queue);
+  silc_task_queue_alloc(&schedule->generic_queue);
 
   /* Initialize the scheduler */
-  schedule->fd_queue = *fd_queue;
-  schedule->timeout_queue = *timeout_queue;
-  schedule->generic_queue = *generic_queue;
-  schedule->fd_list.fd = silc_calloc(max_fd, sizeof(*schedule->fd_list.fd));
-  schedule->fd_list.last_fd = 0;
-  schedule->fd_list.max_fd = max_fd;
+  schedule->fd_list = silc_calloc(max_tasks, sizeof(*schedule->fd_list));
+  schedule->max_fd = max_tasks;
   schedule->timeout = NULL;
   schedule->valid = TRUE;
-  FD_ZERO(&schedule->in);
-  FD_ZERO(&schedule->out);
-  schedule->max_fd = -1;
-  for (i = 0; i < max_fd; i++)
-    schedule->fd_list.fd[i] = -1;
 
+  /* Allocate scheduler lock */
   silc_mutex_alloc(&schedule->lock);
 
-  /* Initialize the wakeup */
-  schedule->wakeup = silc_schedule_wakeup_init(schedule->fd_queue);
+  /* Initialize the wakeup, for multi-threads support */
+  schedule->wakeup = silc_schedule_wakeup_init(schedule);
 
   return schedule;
 }
@@ -202,33 +222,22 @@ SilcSchedule silc_schedule_init(SilcTaskQueue *fd_queue,
 
 bool silc_schedule_uninit(SilcSchedule schedule)
 {
-
   SILC_LOG_DEBUG(("Uninitializing scheduler"));
 
   if (schedule->valid == TRUE)
     return FALSE;
 
   /* Unregister all tasks */
-  if (schedule->fd_queue)
-    silc_task_remove(schedule->fd_queue, SILC_ALL_TASKS);
-  if (schedule->timeout_queue)
-    silc_task_remove(schedule->timeout_queue, SILC_ALL_TASKS);
-  if (schedule->generic_queue)
-    silc_task_remove(schedule->generic_queue, SILC_ALL_TASKS);
+  silc_schedule_task_remove(schedule->fd_queue, SILC_ALL_TASKS);
+  silc_schedule_task_remove(schedule->timeout_queue, SILC_ALL_TASKS);
+  silc_schedule_task_remove(schedule->generic_queue, SILC_ALL_TASKS);
 
   /* Unregister all task queues */
-  if (schedule->fd_queue)
-    silc_task_queue_free(schedule->fd_queue);
-  if (schedule->timeout_queue)
-    silc_task_queue_free(schedule->timeout_queue);
-  if (schedule->generic_queue)
-    silc_task_queue_free(schedule->generic_queue);
-
-  /* Clear the fd list */
-  if (schedule->fd_list.fd) {
-    memset(schedule->fd_list.fd, -1, schedule->fd_list.max_fd);
-    silc_free(schedule->fd_list.fd);
-  }
+  silc_task_queue_free(schedule->fd_queue);
+  silc_task_queue_free(schedule->timeout_queue);
+  silc_task_queue_free(schedule->generic_queue);
+
+  silc_free(schedule->fd_list);
 
   /* Uninit the wakeup */
   silc_schedule_wakeup_uninit(schedule->wakeup);
@@ -250,361 +259,244 @@ void silc_schedule_stop(SilcSchedule schedule)
   silc_mutex_unlock(schedule->lock);
 }
 
-/* Sets a file descriptor to be listened by select() in scheduler. One can
-   call this directly if wanted. This can be called multiple times for
-   one file descriptor to set different iomasks. */
+/* Executes nontimeout tasks. It then checks whether any of ther fd tasks
+   was signaled by the silc_select. If some task was not signaled then
+   all generic tasks are executed for that task. The generic tasks are
+   never executed for task that has explicit fd task set. */
+/* This holds the schedule->lock and the queue locks. */
 
-void silc_schedule_set_listen_fd(SilcSchedule schedule, int fd, uint32 iomask)
+static void silc_schedule_dispatch_nontimeout(SilcSchedule schedule)
 {
-  silc_mutex_lock(schedule->lock);
+  SilcTask task;
+  int i;
 
-  schedule->fd_list.fd[fd] = iomask;
-  
-  if (fd > schedule->fd_list.last_fd)
-    schedule->fd_list.last_fd = fd;
+  for (i = 0; i <= schedule->last_fd; i++) {
+    if (schedule->fd_list[i].events == 0)
+      continue;
 
-  silc_mutex_unlock(schedule->lock);
+    /* First check whether this fd has task in the fd queue */
+    silc_mutex_lock(schedule->fd_queue->lock);
+    task = silc_task_find(schedule->fd_queue, schedule->fd_list[i].fd);
+    silc_mutex_unlock(schedule->fd_queue->lock);
+
+    /* If the task was found then execute its callbacks. If not then
+       execute all generic tasks for that fd. */
+    if (task) {
+      /* Validity of the task is checked always before and after
+        execution beacuse the task might have been unregistered
+        in the callback function, ie. it is not valid anymore. */
+      silc_mutex_lock(schedule->fd_queue->lock);
+
+      /* Is the task ready for reading */
+      if (task->valid && schedule->fd_list[i].revents & SILC_TASK_READ) {
+       silc_mutex_unlock(schedule->fd_queue->lock);
+       silc_mutex_unlock(schedule->lock);
+       task->callback(schedule, SILC_TASK_READ, task->fd, task->context);
+       silc_mutex_lock(schedule->lock);
+       silc_mutex_lock(schedule->fd_queue->lock);
+      }
+
+      /* Is the task ready for writing */
+      if (task->valid && schedule->fd_list[i].revents & SILC_TASK_WRITE) {
+       silc_mutex_unlock(schedule->fd_queue->lock);
+       silc_mutex_unlock(schedule->lock);
+       task->callback(schedule, SILC_TASK_WRITE, task->fd, task->context);
+       silc_mutex_lock(schedule->lock);
+       silc_mutex_lock(schedule->fd_queue->lock);
+      }
+
+      if (!task->valid)
+       silc_schedule_task_remove(schedule->fd_queue, task);
+
+      silc_mutex_unlock(schedule->fd_queue->lock);
+    } else {
+      /* Run generic tasks for this fd. */
+
+      silc_mutex_lock(schedule->generic_queue->lock);
+      if (!schedule->generic_queue->task) {
+       silc_mutex_unlock(schedule->generic_queue->lock);
+       continue;
+      }
+
+      task = schedule->generic_queue->task;
+      while(1) {
+       /* Validity of the task is checked always before and after
+          execution beacuse the task might have been unregistered
+          in the callback function, ie. it is not valid anymore. */
+
+       /* Is the task ready for reading */                             
+       if (task->valid && schedule->fd_list[i].revents & SILC_TASK_READ) {
+         silc_mutex_unlock(schedule->generic_queue->lock);
+         silc_mutex_unlock(schedule->lock);
+         task->callback(schedule, SILC_TASK_READ, schedule->fd_list[i].fd, 
+                        task->context);
+         silc_mutex_lock(schedule->lock);
+         silc_mutex_lock(schedule->generic_queue->lock);
+       }
+
+       /* Is the task ready for writing */                             
+       if (task->valid && schedule->fd_list[i].revents & SILC_TASK_WRITE) {
+         silc_mutex_unlock(schedule->generic_queue->lock);
+         silc_mutex_unlock(schedule->lock);
+         task->callback(schedule, SILC_TASK_WRITE, schedule->fd_list[i].fd, 
+                        task->context);
+         silc_mutex_lock(schedule->lock);
+         silc_mutex_lock(schedule->generic_queue->lock);
+       }
+
+       if (!task->valid) {
+         /* Invalid (unregistered) tasks are removed from the
+            task queue. */
+         if (schedule->generic_queue->task == task->next) {
+           silc_schedule_task_remove(schedule->generic_queue, task);
+           silc_mutex_unlock(schedule->generic_queue->lock);
+           break;
+         }
+
+         task = task->next;
+         silc_schedule_task_remove(schedule->generic_queue, task);
+         continue;
+       }
+
+       /* Break if there isn't more tasks in the queue */
+       if (schedule->generic_queue->task == task->next)
+         break;
+
+       task = task->next;
+      }                        
+
+      silc_mutex_unlock(schedule->generic_queue->lock);
+    }
+  }
 }
 
-/* Removes a file descriptor from listen list. */
+/* Executes all tasks whose timeout has expired. The task is removed from
+   the task queue after the callback function has returned. Also, invalid
+   tasks are removed here. We don't have to care about priorities because 
+   tasks are already sorted in their priority order at the registration 
+   phase. */
+/* This holds the schedule->lock and the schedule->timeout_queue->lock */
 
-void silc_schedule_unset_listen_fd(SilcSchedule schedule, int fd)
+static void silc_schedule_dispatch_timeout(SilcSchedule schedule)
 {
-  silc_mutex_lock(schedule->lock);
+  SilcTaskQueue queue = schedule->timeout_queue;
+  SilcTask task;
+  struct timeval curtime;
 
-  schedule->fd_list.fd[fd] = -1;
-  
-  if (fd == schedule->fd_list.last_fd) {
-    int i;
+  SILC_LOG_DEBUG(("Running timeout tasks"));
+
+  silc_gettimeofday(&curtime);
+
+  queue = schedule->timeout_queue;
+  if (queue && queue->task) {
+    task = queue->task;
+
+    /* Walk thorugh all tasks in the particular task queue and run all 
+       the expired tasks. */
+    while(1) {
+      /* Execute the task if the timeout has expired */
+      if (silc_schedule_task_timeout_compare(&task->timeout, &curtime)) {
+        if (task->valid) {
+         silc_mutex_unlock(queue->lock);
+         silc_mutex_unlock(schedule->lock);
+         task->callback(schedule, SILC_TASK_EXPIRE, task->fd, task->context);
+         silc_mutex_lock(schedule->lock);
+         silc_mutex_lock(queue->lock);
+       }
+
+        /* Break if there isn't more tasks in the queue */
+       if (queue->task == task->next) {
+         silc_schedule_task_remove(queue, task);
+         break;
+        }
+
+        task = task->next;
+
+        /* Remove the task from queue */
+        silc_schedule_task_remove(queue, task->prev);
+      } else {
+        /* The timeout hasn't expired, check for next one */
+
+        /* Break if there isn't more tasks in the queue */
+        if (queue->task == task->next)
+          break;
+
+        task = task->next;
+      }
+    }
+  }
+}
 
-    for (i = fd; i >= 0; i--)
-      if (schedule->fd_list.fd[i] != -1)
-       break;
+/* Calculates next timeout for select(). This is the timeout value
+   when at earliest some of the timeout tasks expire. If this is in the
+   past, they will be run now. */
+/* This holds the schedule->lock and the schedule->timeout_queue->lock */
 
-    schedule->fd_list.last_fd = i < 0 ? 0 : i;
-  }
+static void silc_schedule_select_timeout(SilcSchedule schedule)
+{
+  SilcTaskQueue queue = schedule->timeout_queue;
+  SilcTask task;
+  struct timeval curtime;
 
-  silc_mutex_unlock(schedule->lock);
-}
+  /* Get the current time */
+  silc_gettimeofday(&curtime);
+  schedule->timeout = NULL;
 
-/* Executes tasks matching the file descriptor set by select(). The task
-   remains on the task queue after execution. Invalid tasks are removed 
-   here from the task queue. This macro is used by silc_schedule function. 
-   We don't have to care about the tasks priority here because the tasks
-   are sorted in their priority order already at the registration phase. */
-/* This must be called holding the schedule->lock and the
-   schedule->fd_queue->lock. */
-
-#define SILC_SCHEDULE_RUN_TASKS                                                   \
-do {                                                                      \
-  queue = schedule->fd_queue;                                             \
-  if (queue && queue->valid == TRUE && queue->task) {                     \
-    task = queue->task;                                                           \
-                                                                          \
-    /* Walk thorugh all tasks in the particular task queue and            \
-       execute the callback functions of those tasks matching the         \
-       fd set by select(). */                                             \
-    while(1) {                                                            \
-      /* Validity of the task is checked always before and after          \
-        execution beacuse the task might have been unregistered           \
-        in the callback function, ie. it is not valid anymore. */         \
-                                                                          \
-      if (task->valid) {                                                  \
-       /* Task ready for reading */                                       \
-       if ((FD_ISSET(task->fd, &schedule->in)) &&                         \
-           (task->iomask & (1L << SILC_TASK_READ))) {                     \
-          silc_mutex_unlock(queue->lock);                                 \
-          silc_mutex_unlock(schedule->lock);                              \
-         task->callback(queue, SILC_TASK_READ, task->context, task->fd);  \
-          silc_mutex_lock(schedule->lock);                                \
-          silc_mutex_lock(queue->lock);                                           \
-          is_run = TRUE;                                                  \
-       }                                                                  \
-      }                                                                           \
-                                                                          \
-      if (task->valid) {                                                  \
-       /* Task ready for writing */                                       \
-       if ((FD_ISSET(task->fd, &schedule->out)) &&                        \
-           (task->iomask & (1L << SILC_TASK_WRITE))) {                    \
-          silc_mutex_unlock(queue->lock);                                 \
-          silc_mutex_unlock(schedule->lock);                              \
-         task->callback(queue, SILC_TASK_WRITE, task->context, task->fd); \
-          silc_mutex_lock(schedule->lock);                                \
-          silc_mutex_lock(queue->lock);                                           \
-          is_run = TRUE;                                                  \
-       }                                                                  \
-      }                                                                           \
-                                                                          \
-      if (!task->valid) {                                                 \
-       /* Invalid (unregistered) tasks are removed from the               \
-          task queue. */                                                  \
-       if (queue->task == task->next) {                                   \
-         silc_task_remove(queue, task);                                   \
-          break;                                                          \
-        }                                                                 \
-                                                                          \
-        task = task->next;                                                \
-        silc_task_remove(queue, task->prev);                              \
-        continue;                                                         \
-      }                                                                           \
-                                                                          \
-      /* Break if there isn't more tasks in the queue */                  \
-      if (queue->task == task->next)                                      \
-        break;                                                            \
-                                                                          \
-      task = task->next;                                                  \
-    }                                                                     \
-  }                                                                       \
-} while(0)
-
-/* Selects tasks to be listened by select(). These are the non-timeout
-   tasks. This checks the scheduler's fd list. This macro is used by 
-   silc_schedule function. */
-/* This must be called holding schedule->lock. */
-
-#define SILC_SCHEDULE_SELECT_TASKS                             \
-do {                                                           \
-  for (i = 0; i <= schedule->fd_list.last_fd; i++) {           \
-    if (schedule->fd_list.fd[i] != -1) {                       \
-                                                               \
-      /* Set the max fd value for select() to listen */                \
-      if (i > schedule->max_fd)                                        \
-       schedule->max_fd = i;                                   \
-                                                               \
-      /* Add tasks for reading */                              \
-      if ((schedule->fd_list.fd[i] & (1L << SILC_TASK_READ)))  \
-       FD_SET(i, &schedule->in);                               \
-                                                               \
-      /* Add tasks for writing */                              \
-      if ((schedule->fd_list.fd[i] & (1L << SILC_TASK_WRITE))) \
-       FD_SET(i, &schedule->out);                              \
-    }                                                          \
-  }                                                            \
-} while(0)
+  /* First task in the task queue has always the smallest timeout. */
+  task = queue->task;
+  while(1) {
+    if (task && task->valid == TRUE) {
+      /* If the timeout is in past, we will run the task and all other
+        timeout tasks from the past. */
+      if (silc_schedule_task_timeout_compare(&task->timeout, &curtime)) {
+       silc_schedule_dispatch_timeout(schedule);
+                                               
+       /* The task(s) has expired and doesn't exist on the task queue
+          anymore. We continue with new timeout. */
+       queue = schedule->timeout_queue;
+       task = queue->task;
+       if (task == NULL || task->valid == FALSE)
+         break;
+      }
+
+      /* Calculate the next timeout for select() */
+      queue->timeout.tv_sec = task->timeout.tv_sec - curtime.tv_sec;
+      queue->timeout.tv_usec = task->timeout.tv_usec - curtime.tv_usec;
+      if (queue->timeout.tv_sec < 0)
+       queue->timeout.tv_sec = 0;
+
+      /* We wouldn't want to go under zero, check for it. */
+      if (queue->timeout.tv_usec < 0) {
+       queue->timeout.tv_sec -= 1;
+       if (queue->timeout.tv_sec < 0)
+         queue->timeout.tv_sec = 0;
+       queue->timeout.tv_usec += 1000000L;
+      }
+
+      /* We've got the timeout value */
+      break;
+    } else {
+      /* Task is not valid, remove it and try next one. */
+      silc_schedule_task_remove(queue, task);
+      task = queue->task;
+      if (queue->task == NULL)
+       break;
+    }
+  }
 
-/* Executes all tasks whose timeout has expired. The task is removed from
-   the task queue after the callback function has returned. Also, invalid
-   tasks are removed here. The current time must be get before calling this
-   macro. This macro is used by silc_schedule function. We don't have to
-   care about priorities because tasks are already sorted in their priority
-   order at the registration phase. */
-/* This must be called with holding the schedule->lock and the
-   schedule->timeout_queue->lock */
-
-#define SILC_SCHEDULE_RUN_TIMEOUT_TASKS                                        \
-do {                                                                   \
-  queue = schedule->timeout_queue;                                     \
-  if (queue && queue->valid == TRUE && queue->task) {                  \
-    task = queue->task;                                                        \
-                                                                       \
-    /* Walk thorugh all tasks in the particular task queue             \
-       and run all the expired tasks. */                               \
-    while(1) {                                                         \
-      /* Execute the task if the timeout has expired */                        \
-      if (silc_task_timeout_compare(&task->timeout, &curtime)) {       \
-                                                                       \
-        /* Task ready for reading */                                   \
-        if (task->valid) {                                             \
-          if ((task->iomask & (1L << SILC_TASK_READ))) {               \
-            silc_mutex_unlock(queue->lock);                            \
-            silc_mutex_unlock(schedule->lock);                         \
-           task->callback(queue, SILC_TASK_READ,                       \
-                          task->context, task->fd);                    \
-            silc_mutex_lock(schedule->lock);                           \
-            silc_mutex_lock(queue->lock);                              \
-          }                                                            \
-       }                                                               \
-                                                                       \
-        /* Task ready for writing */                                   \
-        if (task->valid) {                                             \
-          if ((task->iomask & (1L << SILC_TASK_WRITE))) {              \
-            silc_mutex_unlock(queue->lock);                            \
-            silc_mutex_unlock(schedule->lock);                         \
-           task->callback(queue, SILC_TASK_WRITE,                      \
-                          task->context, task->fd);                    \
-            silc_mutex_lock(schedule->lock);                           \
-            silc_mutex_lock(queue->lock);                              \
-          }                                                            \
-        }                                                              \
-                                                                       \
-        /* Break if there isn't more tasks in the queue */             \
-       if (queue->task == task->next) {                                \
-         /* Remove the task from queue */                              \
-         silc_task_remove(queue, task);                                \
-         break;                                                        \
-        }                                                              \
-                                                                       \
-        task = task->next;                                             \
-                                                                       \
-        /* Remove the task from queue */                               \
-        silc_task_remove(queue, task->prev);                           \
-      } else {                                                         \
-        /* The timeout hasn't expired, check for next one */           \
-                                                                       \
-        /* Break if there isn't more tasks in the queue */             \
-        if (queue->task == task->next)                                 \
-          break;                                                       \
-                                                                       \
-        task = task->next;                                             \
-      }                                                                        \
-    }                                                                  \
-  }                                                                    \
-} while(0)
+  /* Save the timeout */
+  if (task) {
+    schedule->timeout = &queue->timeout;
+    SILC_LOG_DEBUG(("timeout: sec=%d, usec=%d", schedule->timeout->tv_sec,
+                   schedule->timeout->tv_usec));
+  }
+}
 
-/* Calculates next timeout for select(). This is the timeout value
-   when at earliest some of the timeout tasks expire. If this is in the
-   past, they will be run now. This macro is used by the silc_schedule
-   function. */
-/* This must be called with holding the schedule->lock and the
-   schedule->timeout_queue->lock */
-
-#define SILC_SCHEDULE_SELECT_TIMEOUT                                       \
-do {                                                                       \
-  if (schedule->timeout_queue && schedule->timeout_queue->valid == TRUE) {  \
-    queue = schedule->timeout_queue;                                       \
-    task = NULL;                                                           \
-                                                                           \
-    /* Get the current time */                                             \
-    silc_gettimeofday(&curtime);                                           \
-    schedule->timeout = NULL;                                              \
-                                                                           \
-    /* First task in the task queue has always the smallest timeout. */            \
-    task = queue->task;                                                            \
-    while(1) {                                                             \
-      if (task && task->valid == TRUE) {                                   \
-                                                                           \
-       /* If the timeout is in past, we will run the task and all other    \
-          timeout tasks from the past. */                                  \
-       if (silc_task_timeout_compare(&task->timeout, &curtime)) {          \
-         SILC_SCHEDULE_RUN_TIMEOUT_TASKS;                                  \
-                                                                           \
-         /* The task(s) has expired and doesn't exist on the task queue    \
-            anymore. We continue with new timeout. */                      \
-          queue = schedule->timeout_queue;                                 \
-          task = queue->task;                                              \
-          if (task == NULL || task->valid == FALSE)                        \
-            break;                                                         \
-         goto cont;                                                        \
-        } else {                                                           \
- cont:                                                                     \
-          /* Calculate the next timeout for select() */                            \
-          queue->timeout.tv_sec = task->timeout.tv_sec - curtime.tv_sec;    \
-          queue->timeout.tv_usec = task->timeout.tv_usec - curtime.tv_usec; \
-         if (queue->timeout.tv_sec < 0)                                    \
-            queue->timeout.tv_sec = 0;                                     \
-                                                                           \
-          /* We wouldn't want to go under zero, check for it. */           \
-          if (queue->timeout.tv_usec < 0) {                                \
-            queue->timeout.tv_sec -= 1;                                            \
-           if (queue->timeout.tv_sec < 0)                                  \
-              queue->timeout.tv_sec = 0;                                   \
-            queue->timeout.tv_usec += 1000000L;                                    \
-          }                                                                \
-        }                                                                  \
-        /* We've got the timeout value */                                  \
-       break;                                                              \
-      }        else {                                                              \
-        /* Task is not valid, remove it and try next one. */               \
-       silc_task_remove(queue, task);                                      \
-        task = queue->task;                                                \
-        if (queue->task == NULL)                                           \
-          break;                                                           \
-      }                                                                            \
-    }                                                                      \
-    /* Save the timeout */                                                 \
-    if (task)                                                              \
-      schedule->timeout = &queue->timeout;                                 \
-  }                                                                        \
-} while(0)
-
-/* Execute generic tasks. These are executed only and only if for the
-   specific fd there wasn't other non-timeout tasks. This checks the earlier
-   set fd list, thus the generic tasks apply to all specified fd's. All the
-   generic tasks are executed at once. */
-/* This must be called holding the schedule->lock and the
-   schedule->generic_queue->lock. */
-
-#define SILC_SCHEDULE_RUN_GENERIC_TASKS                                             \
-do {                                                                        \
-  if (is_run == FALSE) {                                                    \
-    SILC_LOG_DEBUG(("Running generic tasks"));                              \
-    for (i = 0; i <= schedule->fd_list.last_fd; i++)                        \
-      if (schedule->fd_list.fd[i] != -1) {                                  \
-                                                                            \
-       /* Check whether this fd is select()ed. */                           \
-       if ((FD_ISSET(i, &schedule->in)) || (FD_ISSET(i, &schedule->out))) { \
-                                                                            \
-         /* It was selected. Now find the tasks from task queue and execute \
-            all generic tasks. */                                           \
-         if (schedule->generic_queue && schedule->generic_queue->valid) {   \
-           queue = schedule->generic_queue;                                 \
-                                                                            \
-           if (!queue->task)                                                \
-             break;                                                         \
-                                                                            \
-           task = queue->task;                                              \
-                                                                            \
-           while(1) {                                                       \
-             /* Validity of the task is checked always before and after     \
-                execution beacuse the task might have been unregistered     \
-                in the callback function, ie. it is not valid anymore. */   \
-                                                                            \
-             if (task->valid && schedule->fd_list.fd[i] != -1) {            \
-               /* Task ready for reading */                                 \
-               if ((schedule->fd_list.fd[i] & (1L << SILC_TASK_READ))) {    \
-                  silc_mutex_unlock(queue->lock);                           \
-                  silc_mutex_unlock(schedule->lock);                        \
-                 task->callback(queue, SILC_TASK_READ,                      \
-                                task->context, i);                          \
-                  silc_mutex_lock(schedule->lock);                          \
-                  silc_mutex_lock(queue->lock);                                     \
-               }                                                            \
-             }                                                              \
-                                                                            \
-             if (task->valid && schedule->fd_list.fd[i] != -1) {            \
-               /* Task ready for writing */                                 \
-               if ((schedule->fd_list.fd[i] & (1L << SILC_TASK_WRITE))) {   \
-                  silc_mutex_unlock(queue->lock);                           \
-                  silc_mutex_unlock(schedule->lock);                        \
-                 task->callback(queue, SILC_TASK_WRITE,                     \
-                                task->context, i);                          \
-                  silc_mutex_lock(schedule->lock);                          \
-                  silc_mutex_lock(queue->lock);                                     \
-               }                                                            \
-             }                                                              \
-                                                                            \
-             if (!task->valid) {                                            \
-               /* Invalid (unregistered) tasks are removed from the         \
-                  task queue. */                                            \
-               if (queue->task == task->next) {                             \
-                 silc_task_remove(queue, task);                             \
-                 break;                                                     \
-               }                                                            \
-                                                                            \
-               task = task->next;                                           \
-               silc_task_remove(queue, task->prev);                         \
-               continue;                                                    \
-             }                                                              \
-                                                                            \
-             /* Break if there isn't more tasks in the queue */             \
-             if (queue->task == task->next)                                 \
-               break;                                                       \
-                                                                            \
-             task = task->next;                                             \
-           }                                                                \
-         }                                                                  \
-       }                                                                    \
-      }                                                                             \
-  }                                                                         \
-} while(0)
+/* Runs the scheduler once and then returns. */
 
 bool silc_schedule_one(SilcSchedule schedule, int timeout_usecs)
 {
   struct timeval timeout;
-  int is_run, i;
-  SilcTask task;
-  SilcTaskQueue queue;
-  struct timeval curtime;
   int ret;
 
   SILC_LOG_DEBUG(("In scheduler loop"));
@@ -622,33 +514,12 @@ bool silc_schedule_one(SilcSchedule schedule, int timeout_usecs)
     return FALSE;
   }
 
-  /* Clear everything */
-  FD_ZERO(&schedule->in);
-  FD_ZERO(&schedule->out);
-  schedule->max_fd = -1;
-  is_run = FALSE;
-
   /* Calculate next timeout for silc_select(). This is the timeout value
      when at earliest some of the timeout tasks expire. */
   silc_mutex_lock(schedule->timeout_queue->lock);
-  SILC_SCHEDULE_SELECT_TIMEOUT;
+  silc_schedule_select_timeout(schedule);
   silc_mutex_unlock(schedule->timeout_queue->lock);
 
-  /* Add the file descriptors to the fd sets. These are the non-timeout
-     tasks. The silc_select() listens to these file descriptors. */
-  SILC_SCHEDULE_SELECT_TASKS;
-
-  if (schedule->max_fd == -1 && !schedule->timeout) {
-    if (!schedule->is_locked)
-      silc_mutex_unlock(schedule->lock);
-    return FALSE;
-  }
-
-  if (schedule->timeout) {
-    SILC_LOG_DEBUG(("timeout: sec=%d, usec=%d", schedule->timeout->tv_sec,
-                   schedule->timeout->tv_usec));
-  }
-
   if (timeout_usecs >= 0) {
     timeout.tv_sec = 0;
     timeout.tv_usec = timeout_usecs;
@@ -661,8 +532,8 @@ bool silc_schedule_one(SilcSchedule schedule, int timeout_usecs)
      of the selected file descriptors change status or the selected
      timeout expires. */
   SILC_LOG_DEBUG(("Select"));
-  ret = silc_select(schedule->max_fd + 1, &schedule->in,
-                   &schedule->out, 0, schedule->timeout);
+  ret = silc_select(schedule->fd_list, schedule->last_fd + 1, 
+                   schedule->timeout);
 
   silc_mutex_lock(schedule->lock);
 
@@ -675,22 +546,14 @@ bool silc_schedule_one(SilcSchedule schedule, int timeout_usecs)
     break;
   case 0:
     /* Timeout */
-    SILC_LOG_DEBUG(("Running timeout tasks"));
     silc_mutex_lock(schedule->timeout_queue->lock);
-    silc_gettimeofday(&curtime);
-    SILC_SCHEDULE_RUN_TIMEOUT_TASKS;
+    silc_schedule_dispatch_timeout(schedule);
     silc_mutex_unlock(schedule->timeout_queue->lock);
     break;
   default:
     /* There is some data available now */
     SILC_LOG_DEBUG(("Running non-timeout tasks"));
-    silc_mutex_lock(schedule->fd_queue->lock);
-    SILC_SCHEDULE_RUN_TASKS;
-    silc_mutex_unlock(schedule->fd_queue->lock);
-
-    silc_mutex_lock(schedule->generic_queue->lock);
-    SILC_SCHEDULE_RUN_GENERIC_TASKS;
-    silc_mutex_unlock(schedule->generic_queue->lock);
+    silc_schedule_dispatch_nontimeout(schedule);
     break;
   }
 
@@ -739,3 +602,603 @@ void silc_schedule_wakeup(SilcSchedule schedule)
   silc_mutex_unlock(schedule->lock);
 #endif
 }
+
+/* Add new task to the scheduler */
+
+SilcTask silc_schedule_task_add(SilcSchedule schedule, uint32 fd,
+                               SilcTaskCallback callback, void *context, 
+                               long seconds, long useconds, 
+                               SilcTaskType type, 
+                               SilcTaskPriority priority)
+{
+  SilcTask newtask;
+  SilcTaskQueue queue;
+  int timeout = FALSE;
+
+  SILC_LOG_DEBUG(("Registering new task, fd=%d type=%d priority=%d", fd, 
+                 type, priority));
+
+  queue = SILC_SCHEDULE_GET_QUEUE(type);
+    
+  /* If the task is generic task, we check whether this task has already
+     been registered. Generic tasks are registered only once and after that
+     the same task applies to all file descriptors to be registered. */
+  if (type == SILC_TASK_GENERIC) {
+    silc_mutex_lock(queue->lock);
+
+    if (queue->task) {
+      SilcTask task = queue->task;
+      while(1) {
+       if ((task->callback == callback) && (task->context == context)) {
+         SILC_LOG_DEBUG(("Found matching generic task, using the match"));
+         
+         silc_mutex_unlock(queue->lock);
+
+         /* Add the fd to be listened, the task found now applies to this
+            fd as well. */
+         silc_schedule_set_listen_fd(schedule, fd, SILC_TASK_READ);
+         return task;
+       }
+       
+       if (queue->task == task->next)
+         break;
+       
+       task = task->next;
+      }
+    }
+
+    silc_mutex_unlock(queue->lock);
+  }
+
+  newtask = silc_calloc(1, sizeof(*newtask));
+  newtask->fd = fd;
+  newtask->context = context;
+  newtask->callback = callback;
+  newtask->valid = TRUE;
+  newtask->priority = priority;
+  newtask->type = type;
+  newtask->next = newtask;
+  newtask->prev = newtask;
+
+  /* Create timeout if marked to be timeout task */
+  if (((seconds + useconds) > 0) && (type == SILC_TASK_TIMEOUT)) {
+    silc_gettimeofday(&newtask->timeout);
+    newtask->timeout.tv_sec += seconds + (useconds / 1000000L);
+    newtask->timeout.tv_usec += (useconds % 1000000L);
+    if (newtask->timeout.tv_usec > 999999L) {
+      newtask->timeout.tv_sec += 1;
+      newtask->timeout.tv_usec -= 1000000L;
+    }
+    timeout = TRUE;
+  }
+
+  /* If the task is non-timeout task we have to tell the scheduler that we
+     would like to have these tasks scheduled at some odd distant future. */
+  if (type != SILC_TASK_TIMEOUT)
+    silc_schedule_set_listen_fd(schedule, fd, SILC_TASK_READ);
+
+  silc_mutex_lock(queue->lock);
+
+  /* Is this first task of the queue? */
+  if (queue->task == NULL) {
+    queue->task = newtask;
+    silc_mutex_unlock(queue->lock);
+    return newtask;
+  }
+
+  if (timeout)
+    newtask = silc_task_add_timeout(queue, newtask, priority);
+  else
+    newtask = silc_task_add(queue, newtask, priority);
+
+  silc_mutex_unlock(queue->lock);
+
+  return newtask;
+}
+
+/* Removes a task from the scheduler */
+
+void silc_schedule_task_del(SilcSchedule schedule, SilcTask task)
+{
+  SilcTaskQueue queue = SILC_SCHEDULE_GET_QUEUE(task->type);
+
+  /* Unregister all tasks */
+  if (task == SILC_ALL_TASKS) {
+    SilcTask next;
+    SILC_LOG_DEBUG(("Unregistering all tasks at once"));
+
+    silc_mutex_lock(queue->lock);
+
+    if (!queue->task) {
+      silc_mutex_unlock(queue->lock);
+      return;
+    }
+
+    next = queue->task;
+    
+    while(1) {
+      if (next->valid)
+       next->valid = FALSE;
+      if (queue->task == next->next)
+       break;
+      next = next->next;
+    }
+
+    silc_mutex_unlock(queue->lock);
+    return;
+  }
+
+  SILC_LOG_DEBUG(("Unregistering task"));
+
+  silc_mutex_lock(queue->lock);
+
+  /* Unregister the specific task */
+  if (task->valid)
+    task->valid = FALSE;
+
+  silc_mutex_unlock(queue->lock);
+}
+
+/* Remove task by fd */
+
+void silc_schedule_task_del_by_fd(SilcSchedule schedule, uint32 fd)
+{
+  silc_task_del_by_fd(schedule->timeout_queue, fd);
+  silc_task_del_by_fd(schedule->fd_queue, fd);
+  silc_task_del_by_fd(schedule->generic_queue, fd);
+}
+
+/* Remove task by task callback. */
+
+void silc_schedule_task_del_by_callback(SilcSchedule schedule,
+                                       SilcTaskCallback callback)
+{
+  silc_task_del_by_callback(schedule->timeout_queue, callback);
+  silc_task_del_by_callback(schedule->fd_queue, callback);
+  silc_task_del_by_callback(schedule->generic_queue, callback);
+}
+
+/* Remove task by context. */
+
+void silc_schedule_task_del_by_context(SilcSchedule schedule, void *context)
+{
+  silc_task_del_by_context(schedule->timeout_queue, context);
+  silc_task_del_by_context(schedule->fd_queue, context);
+  silc_task_del_by_context(schedule->generic_queue, context);
+}
+
+/* Sets a file descriptor to be listened by select() in scheduler. One can
+   call this directly if wanted. This can be called multiple times for
+   one file descriptor to set different iomasks. */
+
+void silc_schedule_set_listen_fd(SilcSchedule schedule,
+                                uint32 fd, SilcTaskEvent iomask)
+{
+  int i;
+  bool found = FALSE;
+
+  silc_mutex_lock(schedule->lock);
+
+  for (i = 0; i < schedule->max_fd; i++)
+    if (schedule->fd_list[i].fd == fd) {
+      schedule->fd_list[i].fd = fd;
+      schedule->fd_list[i].events = iomask;
+      if (i > schedule->last_fd)
+       schedule->last_fd = i;
+      found = TRUE;
+      break;
+    }
+
+  if (!found)
+    for (i = 0; i < schedule->max_fd; i++)
+      if (schedule->fd_list[i].events == 0) {
+       schedule->fd_list[i].fd = fd;
+       schedule->fd_list[i].events = iomask;
+       if (i > schedule->last_fd)
+         schedule->last_fd = i;
+       break;
+      }
+
+  silc_mutex_unlock(schedule->lock);
+}
+
+/* Removes a file descriptor from listen list. */
+
+void silc_schedule_unset_listen_fd(SilcSchedule schedule, uint32 fd)
+{
+  int i;
+
+  silc_mutex_lock(schedule->lock);
+
+  for (i = 0; i < schedule->max_fd; i++)
+    if (schedule->fd_list[i].fd == fd) {
+      schedule->fd_list[i].fd = 0;
+      schedule->fd_list[i].events = 0;
+      if (schedule->last_fd == i)
+       schedule->last_fd = schedule->max_fd - 1;
+      break;
+    }
+
+  silc_mutex_unlock(schedule->lock);
+}
+
+/* Allocates a newtask task queue into the scheduler */
+
+static void silc_task_queue_alloc(SilcTaskQueue *queue)
+{
+  *queue = silc_calloc(1, sizeof(**queue));
+  silc_mutex_alloc(&(*queue)->lock);
+}
+
+/* Free's a task queue. */
+
+static void silc_task_queue_free(SilcTaskQueue queue)
+{
+  silc_mutex_free(queue->lock);
+  silc_free(queue);
+}
+
+/* Return task by its fd. */
+
+static SilcTask silc_task_find(SilcTaskQueue queue, uint32 fd)
+{
+  SilcTask next;
+
+  if (!queue->task)
+    return NULL;
+
+  next = queue->task;
+
+  while (1) {
+    if (next->fd == fd)
+      return next;
+    if (queue->task == next->next)
+      return NULL;
+    next = next->next;
+  }
+
+  return NULL;
+}
+
+/* Adds a non-timeout task into the task queue. This function is used
+   by silc_task_register function. Returns a pointer to the registered 
+   task. */
+
+static SilcTask silc_task_add(SilcTaskQueue queue, SilcTask newtask, 
+                             SilcTaskPriority priority)
+{
+  SilcTask task, next, prev;
+
+  /* Take the first task in the queue */
+  task = queue->task;
+
+  switch(priority) {
+  case SILC_TASK_PRI_LOW:
+    /* Lowest priority. The task is added at the end of the list. */
+    prev = task->prev;
+    newtask->prev = prev;
+    newtask->next = task;
+    prev->next = newtask;
+    task->prev = newtask;
+    break;
+  case SILC_TASK_PRI_NORMAL:
+    /* Normal priority. The task is added before lower priority tasks
+       but after tasks with higher priority. */
+    prev = task->prev;
+    while(prev != task) {
+      if (prev->priority > SILC_TASK_PRI_LOW)
+       break;
+      prev = prev->prev;
+    }
+    if (prev == task) {
+      /* There are only lower priorities in the list, we will
+        sit before them and become the first task in the queue. */
+      prev = task->prev;
+      newtask->prev = prev;
+      newtask->next = task;
+      task->prev = newtask;
+      prev->next = newtask;
+
+      /* We are now the first task in queue */
+      queue->task = newtask;
+    } else {
+      /* Found a spot from the list, add the task to the list. */
+      next = prev->next;
+      newtask->prev = prev;
+      newtask->next = next;
+      prev->next = newtask;
+      next->prev = newtask;
+    }
+    break;
+  default:
+    silc_free(newtask);
+    return NULL;
+  }
+
+  return newtask;
+}
+
+/* Return the timeout task with smallest timeout. */
+
+static SilcTask silc_task_get_first(SilcTaskQueue queue, SilcTask first)
+{
+  SilcTask prev, task;
+
+  prev = first->prev;
+
+  if (first == prev)
+    return first;
+
+  task = first;
+  while (1) {
+    if (first == prev)
+      break;
+
+    if (silc_schedule_task_timeout_compare(&prev->timeout, &task->timeout))
+      task = prev;
+
+    prev = prev->prev;
+  }
+
+  return task;
+}
+
+/* Adds a timeout task into the task queue. This function is used by
+   silc_task_register function. Returns a pointer to the registered 
+   task. Timeout tasks are sorted by their timeout value in ascending
+   order. The priority matters if there are more than one task with
+   same timeout. */
+
+static SilcTask silc_task_add_timeout(SilcTaskQueue queue, SilcTask newtask,
+                                     SilcTaskPriority priority)
+{
+  SilcTask task, prev, next;
+
+  /* Take the first task in the queue */
+  task = queue->task;
+
+  /* Take last task from the list */
+  prev = task->prev;
+    
+  switch(priority) {
+  case SILC_TASK_PRI_LOW:
+    /* Lowest priority. The task is added at the end of the list. */
+    while(prev != task) {
+
+      /* If we have longer timeout than with the task head of us
+        we have found our spot. */
+      if (silc_schedule_task_timeout_compare(&prev->timeout, 
+                                            &newtask->timeout))
+       break;
+
+      /* If we are equal size of timeout we will be after it. */
+      if (!silc_schedule_task_timeout_compare(&newtask->timeout, 
+                                             &prev->timeout))
+       break;
+
+      /* We have shorter timeout, compare to next one. */
+      prev = prev->prev;
+    }
+    /* Found a spot from the list, add the task to the list. */
+    next = prev->next;
+    newtask->prev = prev;
+    newtask->next = next;
+    prev->next = newtask;
+    next->prev = newtask;
+    
+    if (prev == task) {
+      /* Check if we are going to be the first task in the queue */
+      if (silc_schedule_task_timeout_compare(&prev->timeout, 
+                                            &newtask->timeout))
+       break;
+      if (!silc_schedule_task_timeout_compare(&newtask->timeout, 
+                                             &prev->timeout))
+       break;
+
+      /* We are now the first task in queue */
+      queue->task = newtask;
+    }
+    break;
+  case SILC_TASK_PRI_NORMAL:
+    /* Normal priority. The task is added before lower priority tasks
+       but after tasks with higher priority. */
+    while(prev != task) {
+
+      /* If we have longer timeout than with the task head of us
+        we have found our spot. */
+      if (silc_schedule_task_timeout_compare(&prev->timeout, 
+                                            &newtask->timeout))
+       break;
+
+      /* If we are equal size of timeout, priority kicks in place. */
+      if (!silc_schedule_task_timeout_compare(&newtask->timeout, 
+                                             &prev->timeout))
+       if (prev->priority >= SILC_TASK_PRI_NORMAL)
+         break;
+
+      /* We have shorter timeout or higher priority, compare to next one. */
+      prev = prev->prev;
+    }
+    /* Found a spot from the list, add the task to the list. */
+    next = prev->next;
+    newtask->prev = prev;
+    newtask->next = next;
+    prev->next = newtask;
+    next->prev = newtask;
+    
+    if (prev == task) {
+      /* Check if we are going to be the first task in the queue */
+      if (silc_schedule_task_timeout_compare(&prev->timeout, 
+                                            &newtask->timeout))
+       break;
+      if (!silc_schedule_task_timeout_compare(&newtask->timeout, 
+                                             &prev->timeout))
+       if (prev->priority >= SILC_TASK_PRI_NORMAL)
+         break;
+
+      /* We are now the first task in queue */
+      queue->task = newtask;
+    }
+    break;
+  default:
+    silc_free(newtask);
+    return NULL;
+  }
+
+  return newtask;
+}
+
+/* Removes (unregisters) a task from particular task queue. This function
+   is used internally by scheduler. This must be called holding the 
+   queue->lock. */
+
+static int silc_schedule_task_remove(SilcTaskQueue queue, SilcTask task)
+{
+  SilcTask first, old, next;
+
+  if (!queue)
+    return FALSE;
+
+  if (!queue->task) {
+    return FALSE;
+  }
+
+  first = queue->task;
+
+  /* Unregister all tasks in queue */
+  if (task == SILC_ALL_TASKS) {
+    SILC_LOG_DEBUG(("Removing all tasks at once"));
+    next = first;
+
+    while(1) {
+      next = next->next;
+      silc_free(next->prev);
+      if (next == first)
+       break;
+    }
+
+    queue->task = NULL;
+    return TRUE;
+  }
+
+  SILC_LOG_DEBUG(("Removing task"));
+
+  /* Unregister the task */
+  old = first;
+  while(1) {
+    if (old == task) {
+      SilcTask prev, next;
+
+      prev = old->prev;
+      next = old->next;
+      prev->next = next;
+      next->prev = prev;
+
+      if (prev == old && next == old)
+       queue->task = NULL;
+      if (queue->task == old)
+       queue->task = silc_task_get_first(queue, next);
+      
+      silc_free(old);
+      return TRUE;
+    }
+    old = old->prev;
+
+    if (old == first) {
+      return FALSE;
+    }
+  }
+}
+
+/* Compare two time values. If the first argument is smaller than the
+   second this function returns TRUE. */
+
+static int silc_schedule_task_timeout_compare(struct timeval *smaller, 
+                                             struct timeval *bigger)
+{
+  if ((smaller->tv_sec < bigger->tv_sec) ||
+      ((smaller->tv_sec == bigger->tv_sec) &&
+       (smaller->tv_usec < bigger->tv_usec)))
+    return TRUE;
+
+  return FALSE;
+}
+
+static void silc_task_del_by_fd(SilcTaskQueue queue, uint32 fd)
+{
+  SilcTask next;
+
+  SILC_LOG_DEBUG(("Unregister task by fd"));
+
+  silc_mutex_lock(queue->lock);
+
+  if (!queue->task) {
+    silc_mutex_unlock(queue->lock);
+    return;
+  }
+
+  next = queue->task;
+
+  while(1) {
+    if (next->fd == fd)
+      next->valid = FALSE;
+    if (queue->task == next->next)
+      break;
+    next = next->next;
+  }
+
+  silc_mutex_unlock(queue->lock);
+}
+
+static void silc_task_del_by_callback(SilcTaskQueue queue,
+                                     SilcTaskCallback callback)
+{
+  SilcTask next;
+
+  SILC_LOG_DEBUG(("Unregister task by callback"));
+
+  silc_mutex_lock(queue->lock);
+
+  if (!queue->task) {
+    silc_mutex_unlock(queue->lock);
+    return;
+  }
+
+  next = queue->task;
+
+  while(1) {
+    if (next->callback == callback)
+      next->valid = FALSE;
+    if (queue->task == next->next)
+      break;
+    next = next->next;
+  }
+
+  silc_mutex_unlock(queue->lock);
+}
+
+static void silc_task_del_by_context(SilcTaskQueue queue, void *context)
+{
+  SilcTask next;
+
+  SILC_LOG_DEBUG(("Unregister task by context"));
+
+  silc_mutex_lock(queue->lock);
+
+  if (!queue->task) {
+    silc_mutex_unlock(queue->lock);
+    return;
+  }
+
+  next = queue->task;
+
+  while(1) {
+    if (next->context == context)
+      next->valid = FALSE;
+    if (queue->task == next->next)
+      break;
+    next = next->next;
+  }
+
+  silc_mutex_unlock(queue->lock);
+}
index 21ec78271d4d87e7a67bbe0eccd973128c455951..8866f700a1c2a7e177d69e99d93ac1719d0e6806 100644 (file)
  * the scheduler's run function returns the application is considered to be 
  * ended.
  *
+ * On WIN32 systems the SILC Scheduler is also designed to work as the main
+ * loop of the GUI application. It can handle all Windows messages and
+ * it dispatches them from the scheduler and thus makes it possible to
+ * create GUI applications. The scheduler can also handle all kinds of
+ * WIN32 handles, this includes sockets created by the SILC Net API routines,
+ * WSAEVENT handle objects and arbitrary WIN32 HANDLE objects.
+ *
  * The SILC Scheduler supports multi-threads as well. The actual scheduler
  * must be run in single-thread but other threads may register new tasks
  * and unregister old tasks.  However, it is enforced that the actual
  * which makes it possible to allocate several schedulers for one application.
  * Since the scheduler must be run in single-thread, a multi-threaded
  * application could be created by allocating own scheduler for each of the
- * worker threads. However, in this case the schedulers must not share
- * same task queues. Each of the schedulers must allocate their own
- * task queues.
- *
- * See the SILC Task API for task management interface. It is used to 
- * register and unregister the actual tasks.
+ * worker threads.
  *
  */
 
  ***/
 typedef struct SilcScheduleStruct *SilcSchedule;
 
-/* Prototypes */
+/****s* silcutil/SilcScheduleAPI/SilcTask
+ *
+ * NAME
+ * 
+ *    typedef struct SilcTaskStruct *SilcTask;
+ *
+ * DESCRIPTION
+ *
+ *    This object represents one task in the scheduler.  It is allocated
+ *    by the silc_schedule_task_add function and freed by one of the
+ *    silc_schedule_task_del* functions.
+ *
+ ***/
+typedef struct SilcTaskStruct *SilcTask;
+
+/****d* silcutil/SilcScheduleAPI/SilcTaskType
+ *
+ * NAME
+ * 
+ *    typedef enum { ... } SilcTaskType;
+ *
+ * DESCRIPTION
+ *
+ *    SILC has three types of tasks, non-timeout tasks (tasks that perform
+ *    over file descriptors), timeout tasks and generic tasks (tasks that
+ *    apply to every file descriptor). This type is sent as argument for the 
+ *    task registering function, silc_schedule_task_add.
+ *
+ * SOURCE
+ */
+typedef enum {
+  /* File descriptor task that performs some event over file descriptors.
+     These tasks are for example network connections. */
+  SILC_TASK_FD,
+  
+  /* Timeout tasks are tasks that are executed after the specified 
+     time has elapsed. After the task is executed the task is removed
+     automatically from the scheduler. It is safe to re-register the
+     task in task callback. It is also safe to unregister a task in
+     the task callback. */
+  SILC_TASK_TIMEOUT,
+
+  /* Generic tasks are non-timeout tasks and they apply to all file 
+     descriptors, except to those that have explicitly registered a 
+     non-timeout task. These tasks are there to make it simpler and faster 
+     to execute common code that applies to all connections. These are,
+     for example, receiving packets from network and sending packets to
+     network. It doesn't make much sense to register a task that receives
+     a packet from network to every connection when you can have one task
+     that applies to all connections. This is what generic tasks are for-
+     Generic tasks are not bound to any specific file descriptor, however,
+     the correct file descriptor must be passed as argument to task
+     registering function. */
+  SILC_TASK_GENERIC,
+} SilcTaskType;
+/***/
+
+/****d* silcutil/SilcScheduleAPI/SilcTaskEvent
+ *
+ * NAME
+ * 
+ *    typedef enum { ... } SilcTaskEvent;
+ *
+ * DESCRIPTION
+ *
+ *    SILC Task event types.  The event type indicates the occurred
+ *    event of the task.  This type will be given as argument to the
+ *    SilcTaskCallback function to indicate the event for the caller.
+ *    The SILC_TASK_READ and SILC_TASK_WRITE may be set by the caller
+ *    of the silc_schedule_set_listen_fd if the caller needs to control
+ *    the events for the task. The SILC_TASK_TIMEOUT is set always only
+ *    by the scheduler when timeout for timeout task occurs.
+ *
+ * SOURCE
+ */
+typedef enum {
+  SILC_TASK_READ      = 0x0001,                 /* Reading */
+  SILC_TASK_WRITE     = 0x0002,                 /* Writing */
+  SILC_TASK_EXPIRE    = 0x0004,                 /* Timeout */
+} SilcTaskEvent;
+/***/
+
+/****d* silcutil/SilcScheduleAPI/SilcTaskPriority
+ *
+ * NAME
+ * 
+ *    typedef enum { ... } SilcTaskPriority
+ *
+ * DESCRIPTION
+ *
+ *    Task priorities. Tasks may be registered with different priorities.
+ *    This type defines the different task priorities. The priorities
+ *    behaves same for all type of tasks, fd tasks, timeout tasks and
+ *    generic tasks.
+ *
+ * SOURCE
+ */
+typedef enum {
+  /* Lowest priority. The task is scheduled to run after its timeout
+     has expired only and only when every other task with higher priority 
+     has already been run. For non-timeout tasks this priority behaves
+     same way. Life is not fair for tasks with this priority. */
+  SILC_TASK_PRI_LOW,
+
+  /* Normal priority that is used mostly in Silc. This is priority that
+     should always be used unless you specificly need some other priority.
+     The scheduler will run this task as soon as its timeout has expired.
+     For non-timeout tasks this priority behaves same way. Tasks are run 
+     in FIFO (First-In-First-Out) order. */
+  SILC_TASK_PRI_NORMAL,
+} SilcTaskPriority;
+/***/
 
 /****f* silcutil/SilcScheduleAPI/silc_schedule_init
  *
  * SYNOPSIS
  *
- *    SilcSchedule silc_schedule_init(SilcTaskQueue *fd_queue,
- *                                    SilcTaskQueue *timeout_queue,
- *                                    SilcTaskQueue *generic_queue,
- *                                    int max_fd);
+ *    typedef void (*SilcTaskCallback)(SilcSchedule schedule, 
+ *                                     SilcTaskEvent type, uint32 fd, 
+ *                                     void *context);
  *
  * DESCRIPTION
  *
- *    Initializes the scheduler. Sets the non-timeout task queue hook,
- *    the timeout task queue hook, and the generic task queue hook. This 
- *    must be called before the scheduler is able to work. This will
- *    allocate the queue pointers if they are not allocated. Returns the
- *    scheduler context that must be freed by the silc_schedule_uninit 
- *    function.
+ *    The task callback function.  This function will be called by the
+ *    scheduler when some event of the task is performed.  For example,
+ *    when data is available from the connection this will be called.
+ *
+ *    The `schedule' is the scheduler context, the `type' is the indicated
+ *    event, the `fd' is the file descriptor of the task and the `context'
+ *    is a caller specified context. If multiple events occurred this
+ *    call is called separately for all events.
+ *
+ *    To specify task callback function in the application using the
+ *    SILC_TASK_CALLBACK and SILC_TASK_CALLBACK_GLOBAL macros is
+ *    recommended.
  *
  ***/
-SilcSchedule silc_schedule_init(SilcTaskQueue *fd_queue,
-                               SilcTaskQueue *timeout_queue,
-                               SilcTaskQueue *generic_queue,
-                               int max_fd);
+typedef void (*SilcTaskCallback)(SilcSchedule schedule, SilcTaskEvent type,
+                                uint32 fd, void *context);
 
-/****f* silcutil/SilcScheduleAPI/silc_schedule_uninit
+/* Macros */
+
+/****d* silcutil/SilcScheduleAPI/SILC_ALL_TASKS
  *
- * SYNOPSIS
+ * NAME
+ * 
+ *    #define SILC_ALL_TASKS ...
  *
- *    bool silc_schedule_uninit(SilcSchedule schedule);
+ * DESCRIPTION
+ *
+ *    Marks for all tasks in the scheduler. This can be passed to 
+ *    silc_schedule_task_del function to delete all tasks at once.
+ *
+ * SOURCE
+ */
+#define SILC_ALL_TASKS ((SilcTask)1)
+/***/
+
+/****d* silcutil/SilcScheduleAPI/SILC_TASK_CALLBACK
+ *
+ * NAME
+ * 
+ *    #define SILC_TASK_CALLBACK ...
  *
  * DESCRIPTION
  *
- *    Uninitializes the schedule. This is called when the program is ready
- *    to end. This removes all tasks and task queues. Returns FALSE if the
- *    scheduler could not be uninitialized. This happens when the scheduler
- *    is still valid and silc_schedule_stop has not been called.
+ *    Generic macro to define task callback functions. This defines a
+ *    static function with name `func' as a task callback function.
  *
- ***/
-bool silc_schedule_uninit(SilcSchedule schedule);
+ * SOURCE
+ */
+#define SILC_TASK_CALLBACK(func)                               \
+static void func(SilcSchedule schedule, SilcTaskEvent type,    \
+                uint32 fd, void *context)
+/***/
 
-/****f* silcutil/SilcScheduleAPI/silc_schedule_stop
+/****d* silcutil/SilcScheduleAPI/SILC_TASK_CALLBACK
+ *
+ * NAME
+ * 
+ *    #define SILC_TASK_CALLBACK_GLOBAL ...
+ *
+ * DESCRIPTION
+ *
+ *    Generic macro to define task callback functions. This defines a
+ *    function with name `func' as a task callback function.  This
+ *    differs from SILC_TASK_CALLBACK in that the defined function is
+ *    not static function.
+ *
+ * SOURCE
+ */
+#define SILC_TASK_CALLBACK_GLOBAL(func)                        \
+void func(SilcSchedule schedule, SilcTaskEvent type,   \
+         uint32 fd, void *context)
+/***/
+
+/* Prototypes */
+
+/****f* silcutil/SilcScheduleAPI/silc_schedule_init
  *
  * SYNOPSIS
  *
- *    void silc_schedule_stop(SilcSchedule schedule);
+ *    SilcSchedule silc_schedule_init(int max_tasks);
  *
  * DESCRIPTION
  *
- *    Stops the scheduler even if it is not supposed to be stopped yet. 
- *    After calling this, one must call silc_schedule_uninit (after the 
- *    silc_schedule has returned).
+ *    Initializes the scheduler. This returns the scheduler context that
+ *    is given as arugment usually to all silc_schedule_* functions.
+ *    The `max_tasks' indicates the number of maximum tasks that the
+ *    scheduler can handle.
  *
  ***/
-void silc_schedule_stop(SilcSchedule schedule);
+SilcSchedule silc_schedule_init(int max_tasks);
 
-/****f* silcutil/SilcScheduleAPI/silc_schedule_set_listen_fd
+/****f* silcutil/SilcScheduleAPI/silc_schedule_uninit
  *
  * SYNOPSIS
  *
- *    void silc_schedule_set_listen_fd(SilcSchedule schedule, 
- *                                     int fd, uint32 iomask);
+ *    bool silc_schedule_uninit(SilcSchedule schedule);
  *
  * DESCRIPTION
  *
- *    Sets a file descriptor to be listened by the scheduler. One can
- *    call this directly if wanted. This can be called multiple times for
- *    one file descriptor to set different iomasks.
+ *    Uninitializes the schedule. This is called when the program is ready
+ *    to end. This removes all tasks from the scheduler. Returns FALSE if the
+ *    scheduler could not be uninitialized. This happens when the scheduler
+ *    is still valid and silc_schedule_stop has not been called.
  *
  ***/
-void silc_schedule_set_listen_fd(SilcSchedule schedule, int fd, uint32 iomask);
+bool silc_schedule_uninit(SilcSchedule schedule);
 
-/****f* silcutil/SilcScheduleAPI/silc_schedule_unset_listen_fd
+/****f* silcutil/SilcScheduleAPI/silc_schedule_stop
  *
  * SYNOPSIS
  *
- *    void silc_schedule_unset_listen_fd(SilcSchedule schedule, int fd);
+ *    void silc_schedule_stop(SilcSchedule schedule);
  *
  * DESCRIPTION
  *
- *    Removes a file descriptor from listen list.  The file descriptor
- *    is not listened by the scheduler after this function.
+ *    Stops the scheduler even if it is not supposed to be stopped yet. 
+ *    After calling this, one must call silc_schedule_uninit (after the 
+ *    silc_schedule has returned).
  *
  ***/
-void silc_schedule_unset_listen_fd(SilcSchedule schedule, int fd);
+void silc_schedule_stop(SilcSchedule schedule);
 
 /****f* silcutil/SilcScheduleAPI/silc_schedule
  *
@@ -211,12 +371,173 @@ bool silc_schedule_one(SilcSchedule schedule, int timeout_usecs);
  *
  *    Wakes up the scheduler. This is used only in multi-threaded
  *    environments where threads may add new tasks or remove old tasks
- *    from task queues. This is called to wake up the scheduler in the
- *    main thread so that it detects the changes in the task queues.
+ *    from the scheduler. This is called to wake up the scheduler in the
+ *    main thread so that it detects the changes in the scheduler.
  *    If threads support is not compiled in this function has no effect.
  *    Implementation of this function may be platform specific.
  *
  ***/
 void silc_schedule_wakeup(SilcSchedule schedule);
 
+/****f* silcutil/SilcScheduleAPI/silc_schedule_task_add
+ *
+ * SYNOPSIS
+ *
+ *    SilcTask silc_schedule_task_add(SilcSchedule schedule, uint32 fd,
+ *                                    SilcTaskCallback callback, 
+ *                                    void *context, 
+ *                                    long seconds, long useconds, 
+ *                                    SilcTaskType type, 
+ *                                    SilcTaskPriority priority);
+ *
+ * DESCRIPTION
+ *
+ *    Registers a new task to the scheduler. This same function is used
+ *    to register all types of tasks. The `type' argument tells what type
+ *    of the task is. Note that when registering non-timeout tasks one
+ *    should also pass 0 as timeout, as the timeout will be ignored anyway. 
+ *    Also, note, that one cannot register timeout task with 0 timeout.
+ *    There cannot be zero timeouts, passing zero means no timeout is used
+ *    for the task and SILC_TASK_FD_TASK is used as default task type in
+ *    this case.
+ *
+ *    The `schedule' is the scheduler context. The `fd' is the file
+ *    descriptor of the task. On WIN32 systems the `fd' is not actual
+ *    file descriptor but some WIN32 event handle. On WIN32 system the `fd'
+ *    may be a socket created by the SILC Net API routines, WSAEVENT object
+ *    created by Winsock2 network routines or arbitrary WIN32 HANDLE object.
+ *    On Unix systems the `fd' is always the real file descriptor.
+ *
+ *    The `callback' is the task callback that will be called when some
+ *    event occurs for this task. The `context' is sent as argument to
+ *    the task `callback' function. For timeout tasks the callback is
+ *    called after the specified timeout has elapsed.
+ *
+ *    If the `type' is SILC_TASK_TIMEOUT then `seconds' and `useconds'
+ *    may be non-zero.  Otherwise they should be zero. The `priority'
+ *    indicates the priority of the task.
+ *
+ *    It is always safe to call this function in any place. New tasks
+ *    may be added also in task callbacks, and in multi-threaded environment
+ *    in other threads as well.
+ *   
+ ***/
+SilcTask silc_schedule_task_add(SilcSchedule schedule, uint32 fd,
+                               SilcTaskCallback callback, void *context, 
+                               long seconds, long useconds, 
+                               SilcTaskType type, 
+                               SilcTaskPriority priority);
+
+/****f* silcutil/SilcScheduleAPI/silc_schedule_task_del
+ *
+ * SYNOPSIS
+ *
+ *    void silc_schedule_task_del(SilcSchedule schedule, SilcTask task);
+ *
+ * DESCRIPTION
+ *
+ *    Deletes the `task' from the scheduler indicated by the `schedule'.
+ *    After deleting the task it is guaranteed that the task callback
+ *    will not be called. If the `task' is SILC_ALL_TASKS then all
+ *    tasks is removed from the scheduler.
+ *
+ *    It is safe to call this function in any place. Tasks may be removed
+ *    in task callbacks (including in the task's own task callback) and
+ *    in multi-threaded environment in other threads as well.
+ *
+ ***/
+void silc_schedule_task_del(SilcSchedule schedule, SilcTask task);
+
+/****f* silcutil/SilcScheduleAPI/silc_schedule_task_del_by_fd
+ *
+ * SYNOPSIS
+ *
+ *    void silc_schedule_task_del_by_fd(SilcSchedule schedule, uint32 fd);
+ *
+ * DESCRIPTION
+ *
+ *    Deletes a task from the scheduler by the specified `fd'.
+ *
+ *    It is safe to call this function in any place. Tasks may be removed
+ *    in task callbacks (including in the task's own task callback) and
+ *    in multi-threaded environment in other threads as well.
+ *
+ ***/
+void silc_schedule_task_del_by_fd(SilcSchedule schedule, uint32 fd);
+
+/****f* silcutil/SilcScheduleAPI/silc_schedule_task_del_by_callback
+ *
+ * SYNOPSIS
+ *
+ *    void silc_schedule_task_del_by_callback(SilcSchedule schedule,
+ *                                            SilcTaskCallback callback);
+ *
+ * DESCRIPTION
+ *
+ *    Deletes a task from the scheduler by the specified `callback' task
+ *    callback function.
+ *
+ *    It is safe to call this function in any place. Tasks may be removed
+ *    in task callbacks (including in the task's own task callback) and
+ *    in multi-threaded environment in other threads as well.
+ *
+ ***/
+void silc_schedule_task_del_by_callback(SilcSchedule schedule,
+                                       SilcTaskCallback callback);
+
+/****f* silcutil/SilcScheduleAPI/silc_schedule_task_del_by_context
+ *
+ * SYNOPSIS
+ *
+ *    void silc_schedule_task_del_by_context(SilcSchedule schedule, 
+ *                                           void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Deletes a task from the scheduler by the specified `context'.
+ *
+ *    It is safe to call this function in any place. Tasks may be removed
+ *    in task callbacks (including in the task's own task callback) and
+ *    in multi-threaded environment in other threads as well.
+ *
+ ***/
+void silc_schedule_task_del_by_context(SilcSchedule schedule, void *context);
+
+/****f* silcutil/SilcScheduleAPI/silc_schedule_set_listen_fd
+ *
+ * SYNOPSIS
+ *
+ *    void silc_schedule_set_listen_fd(SilcSchedule schedule, uint32 fd,
+ *                                     SilcTaskEvent mask);
+ *
+ * DESCRIPTION
+ *
+ *    Sets a file descriptor `fd' to be listened by the scheduler for
+ *    `mask' events.  To tell scheduler not to listen anymore for this
+ *    file descriptor call the silc_schedule_unset_listen_fd function.
+ *    When new task is created with silc_schedule_task_add the event
+ *    for the task's fd is initially set to SILC_TASK_READ. If you need
+ *    to control the task's fd's events you must call this function
+ *    whenever you need to change the events. This can be called multiple
+ *    times to change the events.
+ *
+ ***/
+void silc_schedule_set_listen_fd(SilcSchedule schedule, uint32 fd,
+                                SilcTaskEvent mask);
+
+/****f* silcutil/SilcScheduleAPI/silc_schedule_unset_listen_fd
+ *
+ * SYNOPSIS
+ *
+ *    void silc_schedule_unset_listen_fd(SilcSchedule schedule, uint32 fd);
+ *
+ * DESCRIPTION
+ *
+ *    Tells the scheduler not to listen anymore for the specified
+ *    file descriptor `fd'. No events will be detected for the `fd'
+ *    after calling this function.
+ *
+ ***/
+void silc_schedule_unset_listen_fd(SilcSchedule schedule, uint32 fd);
+
 #endif
index 0fdcb90435b7b2381395e1dc6089121b306183b3..942b30d8664e37ef46b36fd9762d39ccce7219da 100644 (file)
@@ -26,7 +26,7 @@ struct SilcSocketConnectionHBStruct {
   uint32 heartbeat;
   SilcSocketConnectionHBCb hb_callback;
   void *hb_context;
-  void *timeout_queue;
+  SilcSchedule schedule;
   SilcTask hb_task;
   SilcSocketConnection sock;
 };
@@ -35,7 +35,7 @@ struct SilcSocketConnectionHBStruct {
 typedef struct {
   SilcSocketHostLookupCb callback;
   void *context;
-  void *timeout_queue;
+  SilcSchedule schedule;
   SilcSocketConnection sock;
   bool port;
 } *SilcSocketHostLookup;
@@ -72,7 +72,7 @@ void silc_socket_free(SilcSocketConnection sock)
     silc_buffer_free(sock->inbuf);
     silc_buffer_free(sock->outbuf);
     if (sock->hb) {
-      silc_task_unregister(sock->hb->timeout_queue, sock->hb->hb_task);
+      silc_schedule_task_del(sock->hb->schedule, sock->hb->hb_task);
       silc_free(sock->hb->hb_context);
       silc_free(sock->hb);
     }
@@ -104,11 +104,11 @@ SILC_TASK_CALLBACK(silc_socket_heartbeat)
   if (hb->hb_callback)
     hb->hb_callback(hb->sock, hb->hb_context);
 
-  hb->hb_task = silc_task_register(hb->timeout_queue, hb->sock->sock, 
-                                  silc_socket_heartbeat,
-                                  context, hb->heartbeat, 0,
-                                  SILC_TASK_TIMEOUT,
-                                  SILC_TASK_PRI_LOW);
+  hb->hb_task = silc_schedule_task_add(hb->schedule, hb->sock->sock, 
+                                      silc_socket_heartbeat,
+                                      context, hb->heartbeat, 0,
+                                      SILC_TASK_TIMEOUT,
+                                      SILC_TASK_PRI_LOW);
 }
 
 /* Sets the heartbeat timeout and prepares the socket for performing
@@ -117,20 +117,16 @@ SILC_TASK_CALLBACK(silc_socket_heartbeat)
    `hb_callback' function that is called when the `heartbeat' timeout
    expires.  The callback `hb_context' won't be touched by the library
    but will be freed automatically when calling silc_socket_free.  The
-   `timeout_queue' is the application's scheduler timeout queue. */
+   `schedule' is the application's scheduler. */
 
 void silc_socket_set_heartbeat(SilcSocketConnection sock, 
                               uint32 heartbeat,
                               void *hb_context,
                               SilcSocketConnectionHBCb hb_callback,
-                              void *timeout_queue)
+                              SilcSchedule schedule)
 {
-
-  if (!timeout_queue)
-    return;
-
   if (sock->hb) {
-    silc_task_unregister(sock->hb->timeout_queue, sock->hb->hb_task);
+    silc_schedule_task_del(schedule, sock->hb->hb_task);
     silc_free(sock->hb->hb_context);
     silc_free(sock->hb);
   }
@@ -139,13 +135,13 @@ void silc_socket_set_heartbeat(SilcSocketConnection sock,
   sock->hb->heartbeat = heartbeat;
   sock->hb->hb_context = hb_context;
   sock->hb->hb_callback = hb_callback;
-  sock->hb->timeout_queue = timeout_queue;
+  sock->hb->schedule = schedule;
   sock->hb->sock = sock;
-  sock->hb->hb_task = silc_task_register(timeout_queue, sock->sock,
-                                         silc_socket_heartbeat,
-                                         (void *)sock->hb, heartbeat, 0,
-                                         SILC_TASK_TIMEOUT,
-                                         SILC_TASK_PRI_LOW);
+  sock->hb->hb_task = silc_schedule_task_add(schedule, sock->sock,
+                                            silc_socket_heartbeat,
+                                            (void *)sock->hb, heartbeat, 0,
+                                            SILC_TASK_TIMEOUT,
+                                            SILC_TASK_PRI_LOW);
 }
 
 /* Finishing timeout callback that will actually call the user specified
@@ -193,10 +189,10 @@ static void *silc_socket_host_lookup_start(void *context)
   if (!sock->hostname && sock->ip)
     sock->hostname = strdup(sock->ip);
 
-  silc_task_register(lookup->timeout_queue, sock->sock,
-                    silc_socket_host_lookup_finish, lookup, 0, 1,
-                    SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-  silc_task_queue_wakeup(lookup->timeout_queue);
+  silc_schedule_task_add(lookup->schedule, sock->sock,
+                        silc_socket_host_lookup_finish, lookup, 0, 1,
+                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+  silc_schedule_wakeup(lookup->schedule);
 
   return NULL;
 }
@@ -205,30 +201,26 @@ static void *silc_socket_host_lookup_start(void *context)
    specified socket connection. This may be called when the socket
    connection is created and the full IP address and fully qualified
    domain name information is desired. The `callback' with `context'
-   will be called after the lookup is performed. The `timeout_queue'
-   is the application's scheduler timeout queue which the lookup
-   routine needs. If the socket connection is freed during
-   the lookup the library will automatically cancel the lookup and
-   the `callback' will not be called. */
+   will be called after the lookup is performed. The `schedule'
+   is the application's scheduler which the lookup routine needs. If
+   the socket connection is freed during the lookup the library will
+   automatically cancel the lookup and the `callback' will not be called. */
 
 void silc_socket_host_lookup(SilcSocketConnection sock,
                             bool port_lookup,
                             SilcSocketHostLookupCb callback,
                             void *context,
-                            void *timeout_queue)
+                            SilcSchedule schedule)
 {
   SilcSocketHostLookup lookup;
 
   SILC_LOG_DEBUG(("Performing async host lookup"));
 
-  if (!timeout_queue)
-    return;
-
   lookup = silc_calloc(1, sizeof(*lookup));
   lookup->sock = silc_socket_dup(sock);        /* Increase reference counter */
   lookup->callback = callback;
   lookup->context = context;
-  lookup->timeout_queue = timeout_queue;
+  lookup->schedule = schedule;
   lookup->port = port_lookup;
 
   SILC_SET_HOST_LOOKUP(sock);
index 658c3acda1755f12565d1b2b7f6360c553bd6091..20e307403d1e4ec011a1251318343b41ea793a51 100644 (file)
@@ -333,7 +333,7 @@ typedef void (*SilcSocketConnectionHBCb)(SilcSocketConnection sock,
  *                                   uint32 heartbeat,
  *                                   void *hb_context,
  *                                   SilcSocketConnectionHBCb hb_callback,
- *                                   void *timeout_queue);
+ *                                   SilcSchedule schedule);
  *
  * DESCRIPTION
  *
@@ -343,14 +343,14 @@ typedef void (*SilcSocketConnectionHBCb)(SilcSocketConnection sock,
  *    `hb_callback' function that is called when the `heartbeat' timeout
  *    expires.  The callback `hb_context' won't be touched by the library
  *    but will be freed automatically when calling silc_socket_free.  The
- *    `timeout_queue' is the application's scheduler timeout queue.
+ *    `schedule' is the application's scheduler.
  *
  ***/
 void silc_socket_set_heartbeat(SilcSocketConnection sock, 
                               uint32 heartbeat,
                               void *hb_context,
                               SilcSocketConnectionHBCb hb_callback,
-                              void *timeout_queue);
+                              SilcSchedule schedule);
 
 /****f* silcutil/SilcSocketConnectionAPI/SilcSocketHostLookupCb
  *
@@ -375,7 +375,7 @@ typedef void (*SilcSocketHostLookupCb)(SilcSocketConnection sock,
  *    void silc_socket_host_lookup(SilcSocketConnection sock,
  *                                 SilcSocketHostLookupCb callback,
  *                                 void *context,
- *                                 void *timeout_queue);
+ *                                 SilcSchedule schedule);
  *
  * DESCRIPTION
  *
@@ -383,11 +383,11 @@ typedef void (*SilcSocketHostLookupCb)(SilcSocketConnection sock,
  *    specified socket connection. This may be called when the socket
  *    connection is created and the full IP address and fully qualified
  *    domain name information is desired. The `callback' with `context'
- *    will be called after the lookup is performed. The `timeout_queue'
- *    is the application's scheduler timeout queue which the lookup
- *    routine needs. If the socket connection is freed during the
- *    lookup the library will automatically cancel the lookup and
- *    the `callback' will not be called.
+ *    will be called after the lookup is performed. The `schedule'
+ *    is the application's scheduler which the lookup routine needs. 
+ *    If the socket connection is freed during the lookup the library
+ *    will automatically cancel the lookup and the `callback' will not be
+ *    called.
  *
  *    If `port_lookup' is TRUE then the remote port of the socket 
  *    connection is resolved. After the information is resolved they
@@ -401,6 +401,6 @@ void silc_socket_host_lookup(SilcSocketConnection sock,
                             bool port_lookup,
                             SilcSocketHostLookupCb callback,
                             void *context,
-                            void *timeout_queue);
+                            SilcSchedule schedule);
 
 #endif
diff --git a/lib/silcutil/silctask.c b/lib/silcutil/silctask.c
deleted file mode 100644 (file)
index 36bf5d4..0000000
+++ /dev/null
@@ -1,604 +0,0 @@
-/*
-
-  silctask.c
-
-  Author: Pekka Riikonen <priikone@silcnet.org>
-
-  Copyright (C) 1998 - 2001 Pekka Riikonen
-
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-  
-  This program 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.
-
-*/
-/* $Id$ */
-
-#include "silcincludes.h"
-
-/* Routine to compare task timeouts. */
-int silc_task_timeout_compare(struct timeval *smaller, 
-                             struct timeval *bigger);
-
-/* Allocates a new task queue into the Silc. If 'valid' is TRUE the
-   queue becomes valid task queue. If it is FALSE scheduler will skip
-   the queue. */
-
-void silc_task_queue_alloc(SilcSchedule schedule, SilcTaskQueue *new, 
-                          bool valid)
-{
-  SILC_LOG_DEBUG(("Allocating new task queue"));
-
-  *new = silc_calloc(1, sizeof(**new));
-
-  /* Set the pointers */
-  (*new)->schedule = schedule;
-  (*new)->valid = valid;
-  silc_mutex_alloc(&(*new)->lock);
-}
-
-/* Free's a task queue. */
-
-void silc_task_queue_free(SilcTaskQueue queue)
-{
-  silc_mutex_lock(queue->lock);
-  queue->valid = FALSE;
-  silc_mutex_unlock(queue->lock);
-  silc_mutex_free(queue->lock);
-  silc_free(queue);
-}
-
-/* Wakes up the task queue. This actually wakes up the scheduler of this
-   task queue. This is called in multi-threaded environment to wake up
-   the scheduler after adding or removing tasks from the task queue. */
-
-void silc_task_queue_wakeup(SilcTaskQueue queue)
-{
-  silc_schedule_wakeup(queue->schedule);
-}
-
-/* Adds a non-timeout task into the task queue. This function is used
-   by silc_task_register function. Returns a pointer to the registered 
-   task. */
-
-static SilcTask silc_task_add(SilcTaskQueue queue, SilcTask new, 
-                             SilcTaskPriority priority)
-{
-  SilcTask task, next, prev;
-
-  /* Take the first task in the queue */
-  task = queue->task;
-
-  switch(priority) {
-  case SILC_TASK_PRI_LOW:
-    /* Lowest priority. The task is added at the end of the list. */
-    prev = task->prev;
-    new->prev = prev;
-    new->next = task;
-    prev->next = new;
-    task->prev = new;
-    break;
-  case SILC_TASK_PRI_NORMAL:
-    /* Normal priority. The task is added before lower priority tasks
-       but after tasks with higher priority. */
-    prev = task->prev;
-    while(prev != task) {
-      if (prev->priority > SILC_TASK_PRI_LOW)
-       break;
-      prev = prev->prev;
-    }
-    if (prev == task) {
-      /* There are only lower priorities in the list, we will
-        sit before them and become the first task in the queue. */
-      prev = task->prev;
-      new->prev = prev;
-      new->next = task;
-      task->prev = new;
-      prev->next = new;
-
-      /* We are now the first task in queue */
-      queue->task = new;
-    } else {
-      /* Found a spot from the list, add the task to the list. */
-      next = prev->next;
-      new->prev = prev;
-      new->next = next;
-      prev->next = new;
-      next->prev = new;
-    }
-    break;
-  default:
-    silc_free(new);
-    return NULL;
-  }
-
-  return new;
-}
-
-/* Return the timeout task with smallest timeout. */
-
-static SilcTask silc_task_get_first(SilcTaskQueue queue, SilcTask first)
-{
-  SilcTask prev, task;
-
-  prev = first->prev;
-
-  if (first == prev)
-    return first;
-
-  task = first;
-  while (1) {
-    if (first == prev)
-      break;
-
-    if (silc_task_timeout_compare(&prev->timeout, &task->timeout))
-      task = prev;
-
-    prev = prev->prev;
-  }
-
-  return task;
-}
-
-/* Adds a timeout task into the task queue. This function is used by
-   silc_task_register function. Returns a pointer to the registered 
-   task. Timeout tasks are sorted by their timeout value in ascending
-   order. The priority matters if there are more than one task with
-   same timeout. */
-
-static SilcTask silc_task_add_timeout(SilcTaskQueue queue, SilcTask new,
-                                     SilcTaskPriority priority)
-{
-  SilcTask task, prev, next;
-
-  /* Take the first task in the queue */
-  task = queue->task;
-
-  /* Take last task from the list */
-  prev = task->prev;
-    
-  switch(priority) {
-  case SILC_TASK_PRI_LOW:
-    /* Lowest priority. The task is added at the end of the list. */
-    while(prev != task) {
-
-      /* If we have longer timeout than with the task head of us
-        we have found our spot. */
-      if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
-       break;
-
-      /* If we are equal size of timeout we will be after it. */
-      if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
-       break;
-
-      /* We have shorter timeout, compare to next one. */
-      prev = prev->prev;
-    }
-    /* Found a spot from the list, add the task to the list. */
-    next = prev->next;
-    new->prev = prev;
-    new->next = next;
-    prev->next = new;
-    next->prev = new;
-    
-    if (prev == task) {
-      /* Check if we are going to be the first task in the queue */
-      if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
-       break;
-      if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
-       break;
-
-      /* We are now the first task in queue */
-      queue->task = new;
-    }
-    break;
-  case SILC_TASK_PRI_NORMAL:
-    /* Normal priority. The task is added before lower priority tasks
-       but after tasks with higher priority. */
-    while(prev != task) {
-
-      /* If we have longer timeout than with the task head of us
-        we have found our spot. */
-      if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
-       break;
-
-      /* If we are equal size of timeout, priority kicks in place. */
-      if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
-       if (prev->priority >= SILC_TASK_PRI_NORMAL)
-         break;
-
-      /* We have shorter timeout or higher priority, compare to next one. */
-      prev = prev->prev;
-    }
-    /* Found a spot from the list, add the task to the list. */
-    next = prev->next;
-    new->prev = prev;
-    new->next = next;
-    prev->next = new;
-    next->prev = new;
-    
-    if (prev == task) {
-      /* Check if we are going to be the first task in the queue */
-      if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
-       break;
-      if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
-       if (prev->priority >= SILC_TASK_PRI_NORMAL)
-         break;
-
-      /* We are now the first task in queue */
-      queue->task = new;
-    }
-    break;
-  default:
-    silc_free(new);
-    return NULL;
-  }
-
-  return new;
-}
-
-/* Registers a new task to the task queue. Arguments are as follows:
-      
-   SilcTaskQueue queue        Queue where the task is to be registered
-   int fd                     File descriptor
-   SilcTaskCallback cb        Callback function to call
-   void *context              Context to be passed to callback function
-   long seconds               Seconds to timeout
-   long useconds              Microseconds to timeout
-   SilcTaskType type          Type of the task
-   SilcTaskPriority priority  Priority of the task
-   
-   The same function is used to register all types of tasks. The type
-   argument tells what type of the task is. Note that when registering
-   non-timeout tasks one should also pass 0 as timeout as timeout will
-   be ignored anyway. Also, note, that one cannot register timeout task
-   with 0 timeout. There cannot be zero timeouts, passing zero means
-   no timeout is used for the task and SILC_TASK_FD_TASK is used as
-   default task type in this case.
-   
-   One should be careful not to register timeout tasks to the non-timeout
-   task queue, because they will never expire. As one should not register
-   non-timeout tasks to timeout task queue because they will never get
-   scheduled.
-   
-   There is a one distinct difference between timeout and non-timeout
-   tasks when they are executed. Non-timeout tasks remain on the task
-   queue after execution. Timeout tasks, however, are removed from the
-   task queue after they have expired. It is safe to re-register a task 
-   in its own callback function. It is also safe to unregister a task 
-   in a callback function.
-   
-   Generic tasks apply to all file descriptors, however, one still must
-   pass the correct file descriptor to the function when registering
-   generic tasks. */
-
-SilcTask silc_task_register(SilcTaskQueue queue, int fd, 
-                           SilcTaskCallback cb, void *context, 
-                           long seconds, long useconds, 
-                           SilcTaskType type, SilcTaskPriority priority)
-{
-  SilcTask new;
-  int timeout = FALSE;
-
-  SILC_LOG_DEBUG(("Registering new task, fd=%d type=%d priority=%d", 
-                 fd, type, priority));
-
-  /* If the task is generic task, we check whether this task has already
-     been registered. Generic tasks are registered only once and after that
-     the same task applies to all file descriptors to be registered. */
-  if (type == SILC_TASK_GENERIC) {
-    silc_mutex_lock(queue->lock);
-
-    if (queue->task) {
-      SilcTask task = queue->task;
-      while(1) {
-       if ((task->callback == cb) && (task->context == context)) {
-         SILC_LOG_DEBUG(("Found matching generic task, using the match"));
-         
-         silc_mutex_unlock(queue->lock);
-
-         /* Add the fd to be listened, the task found now applies to this
-            fd as well. */
-         silc_schedule_set_listen_fd(queue->schedule, 
-                                     fd, (1L << SILC_TASK_READ));
-         return task;
-       }
-       
-       if (queue->task == task->next)
-         break;
-       
-       task = task->next;
-      }
-    }
-
-    silc_mutex_unlock(queue->lock);
-  }
-
-  new = silc_calloc(1, sizeof(*new));
-  new->fd = fd;
-  new->context = context;
-  new->callback = cb;
-  new->valid = TRUE;
-  new->priority = priority;
-  new->iomask = (1L << SILC_TASK_READ);
-  new->next = new;
-  new->prev = new;
-
-  /* Create timeout if marked to be timeout task */
-  if (((seconds + useconds) > 0) && (type == SILC_TASK_TIMEOUT)) {
-    silc_gettimeofday(&new->timeout);
-    new->timeout.tv_sec += seconds + (useconds / 1000000L);
-    new->timeout.tv_usec += (useconds % 1000000L);
-    if (new->timeout.tv_usec > 999999L) {
-      new->timeout.tv_sec += 1;
-      new->timeout.tv_usec -= 1000000L;
-    }
-    timeout = TRUE;
-  }
-
-  /* If the task is non-timeout task we have to tell the scheduler that we
-     would like to have these tasks scheduled at some odd distant future. */
-  if (type != SILC_TASK_TIMEOUT)
-    silc_schedule_set_listen_fd(queue->schedule, fd, (1L << SILC_TASK_READ));
-
-  silc_mutex_lock(queue->lock);
-
-  /* Is this first task of the queue? */
-  if (queue->task == NULL) {
-    queue->task = new;
-    silc_mutex_unlock(queue->lock);
-    return new;
-  }
-
-  if (timeout)
-    new = silc_task_add_timeout(queue, new, priority);
-  else
-    new = silc_task_add(queue, new, priority);
-
-  silc_mutex_unlock(queue->lock);
-
-  return new;
-}
-
-/* Removes (unregisters) a task from particular task queue. This function
-   is used internally by scheduler. This must be called holding the 
-   queue->lock. */
-
-int silc_task_remove(SilcTaskQueue queue, SilcTask task)
-{
-  SilcTask first, old, next;
-
-  if (!queue)
-    return FALSE;
-
-  if (!queue->task) {
-    return FALSE;
-  }
-
-  first = queue->task;
-
-  /* Unregister all tasks in queue */
-  if (task == SILC_ALL_TASKS) {
-    SILC_LOG_DEBUG(("Removing all tasks at once"));
-    next = first;
-
-    while(1) {
-      next = next->next;
-      silc_free(next->prev);
-      if (next == first)
-       break;
-    }
-
-    queue->task = NULL;
-    return TRUE;
-  }
-
-  SILC_LOG_DEBUG(("Removing task"));
-
-  /* Unregister the task */
-  old = first;
-  while(1) {
-    if (old == task) {
-      SilcTask prev, next;
-
-      prev = old->prev;
-      next = old->next;
-      prev->next = next;
-      next->prev = prev;
-
-      if (prev == old && next == old)
-       queue->task = NULL;
-      if (queue->task == old)
-       queue->task = silc_task_get_first(queue, next);
-      
-      silc_free(old);
-      return TRUE;
-    }
-    old = old->prev;
-
-    if (old == first) {
-      return FALSE;
-    }
-  }
-}
-
-/* Unregisters a task already in the queue. Arguments are as follows:
-   
-   SilcTaskQueue queue      Queue where from the task is unregistered
-   SilcTask task            Task to be unregistered
-   
-   The same function is used to unregister timeout and non-timeout 
-   tasks. One can also unregister all tasks from the queue by passing
-   SILC_ALL_TASKS as task to the function. It is safe to unregister
-   a task in a callback function. */
-
-void silc_task_unregister(SilcTaskQueue queue, SilcTask task)
-{
-
-  /* Unregister all tasks */
-  if (task == SILC_ALL_TASKS) {
-    SilcTask next;
-    SILC_LOG_DEBUG(("Unregistering all tasks at once"));
-
-    silc_mutex_lock(queue->lock);
-
-    if (!queue->task) {
-      silc_mutex_unlock(queue->lock);
-      return;
-    }
-
-    next = queue->task;
-    
-    while(1) {
-      if (next->valid)
-       next->valid = FALSE;
-      if (queue->task == next->next)
-       break;
-      next = next->next;
-    }
-
-    silc_mutex_unlock(queue->lock);
-    return;
-  }
-
-  SILC_LOG_DEBUG(("Unregistering task"));
-
-  silc_mutex_lock(queue->lock);
-
-  /* Unregister the specific task */
-  if (task->valid)
-    task->valid = FALSE;
-
-  silc_mutex_unlock(queue->lock);
-}
-
-/* Unregister a task by file descriptor. This invalidates the task. */
-
-void silc_task_unregister_by_fd(SilcTaskQueue queue, int fd)
-{
-  SilcTask next;
-
-  SILC_LOG_DEBUG(("Unregister task by fd"));
-
-  silc_mutex_lock(queue->lock);
-
-  if (!queue->task) {
-    silc_mutex_unlock(queue->lock);
-    return;
-  }
-
-  next = queue->task;
-
-  while(1) {
-    if (next->fd == fd)
-      next->valid = FALSE;
-    if (queue->task == next->next)
-      break;
-    next = next->next;
-  }
-
-  silc_mutex_unlock(queue->lock);
-}
-
-/* Unregister a task by callback function. This invalidates the task. */
-
-void silc_task_unregister_by_callback(SilcTaskQueue queue, 
-                                     SilcTaskCallback callback)
-{
-  SilcTask next;
-
-  SILC_LOG_DEBUG(("Unregister task by callback"));
-
-  silc_mutex_lock(queue->lock);
-
-  if (!queue->task) {
-    silc_mutex_unlock(queue->lock);
-    return;
-  }
-
-  next = queue->task;
-
-  while(1) {
-    if (next->callback == callback)
-      next->valid = FALSE;
-    if (queue->task == next->next)
-      break;
-    next = next->next;
-  }
-
-  silc_mutex_unlock(queue->lock);
-}
-
-/* Unregister a task by context. This invalidates the task. */
-
-void silc_task_unregister_by_context(SilcTaskQueue queue, void *context)
-{
-  SilcTask next;
-
-  SILC_LOG_DEBUG(("Unregister task by context"));
-
-  silc_mutex_lock(queue->lock);
-
-  if (!queue->task) {
-    silc_mutex_unlock(queue->lock);
-    return;
-  }
-
-  next = queue->task;
-
-  while(1) {
-    if (next->context == context)
-      next->valid = FALSE;
-    if (queue->task == next->next)
-      break;
-    next = next->next;
-  }
-
-  silc_mutex_unlock(queue->lock);
-}
-
-/* Sets the I/O type of the task. The scheduler checks for this value
-   and a task must always have at least one of the I/O types set at 
-   all time. When registering new task the type is set by default to
-   SILC_TASK_READ. If the task doesn't perform reading one must reset
-   the value to SILC_TASK_WRITE.
-   
-   The type sent as argumenet is masked into the task. If the tasks 
-   I/O mask already includes this type this function has no effect. 
-   Only one I/O type can be added at once. If the task must perform
-   both reading and writing one must call this function for value
-   SILC_TASK_WRITE as well. */
-
-void silc_task_set_iotype(SilcTask task, int type)
-{
-  task->iomask |= (1L << type);
-}
-
-/* Resets the mask to the type sent as argument. Note that this resets
-   the previous values to zero and then adds the type sent as argument.
-   This function can be used to remove one of the types masked earlier
-   to the task. */
-
-void silc_task_reset_iotype(SilcTask task, int type)
-{
-  task->iomask = (1L << type);
-}
-
-/* Compare two time values. If the first argument is smaller than the
-   second this function returns TRUE. */
-
-int silc_task_timeout_compare(struct timeval *smaller, 
-                             struct timeval *bigger)
-{
-  if ((smaller->tv_sec < bigger->tv_sec) ||
-      ((smaller->tv_sec == bigger->tv_sec) &&
-       (smaller->tv_usec < bigger->tv_usec)))
-    return TRUE;
-
-  return FALSE;
-}
diff --git a/lib/silcutil/silctask.h b/lib/silcutil/silctask.h
deleted file mode 100644 (file)
index c33a6b2..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
-
-  silctask.h
-
-  Author: Pekka Riikonen <priikone@silcnet.org>
-
-  Copyright (C) 1998 - 2001 Pekka Riikonen
-
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-  
-  This program 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.
-
-*/
-
-#ifndef SILCTASK_H
-#define SILCTASK_H
-
-typedef struct SilcTaskQueueStruct *SilcTaskQueue;
-typedef struct SilcTaskStruct *SilcTask;
-typedef void (*SilcTaskCallback)(void *, int, void *, int);
-
-#include "silcschedule.h"
-
-/* 
-   SILC Task object. 
-
-   int fd
-
-       File descriptor. This usually is a network socket but can be
-       any file descriptor. On generic tasks, that applies to all file
-       descriptors, this is set to -1.
-
-   struct timeval timeout
-  
-       The timeout when this task is supposed to be run. This is defined
-       only if the task is a timeout task.
-
-   void *context;
-
-       Context structure passed to callback function as argument.
-
-   SilcTaskCallback callback
-
-       The callback function Silc scheduler calls when this task is scheduled
-       to be run. First argument is the task queue this task belongs to. This
-       is a void pointer and the task queue has to casted out of it. Second
-       argument is the type of the event just occured inside the scheduler 
-       (SILC_TASK_READ or SILC_TASK_WRITE). Third argument is the context 
-       structure of the task. Last argument is the file descriptor of the
-       task.
-
-   bool valid
-
-       Marks for validity of the task. Task that is not valid scheduler 
-       will skip. This is boolean value.
-
-   int priority
-
-       Priority of the task. This field is used internally only and it
-       should not be touched otherwise.
-
-   int iomask
-
-       I/O mask which tells to the scheduler for what kind of I/O this 
-       task is ready. If the task is ready for both reading and writing
-       SILC_TASK_READ and SILC_TASK_WRITE are masked into this variable.
-       Masking is done by OR'ing (1 << SILC_TASK_*) values. One can check
-       the mask by AND'ing (1L << SILC_TASK_*) against the mask. At the
-       registering of a new task this mask is set to SILC_TASK_READ by
-       default. If a task doesn't perform reading this value must be
-       reset to SILC_TASK_WRITE. If it performs both reading and writing
-       SILC_TASK_WRITE must be added to the mask. A task must always be 
-       ready for at least for one I/O type.
-
-   struct SilcTaskStruct *next
-   struct SilcTaskStruct *prev
-
-       Next and previous task. If the task is first in the list, prev is
-       set to the last task in the list. If the task is last in the list, 
-       next is set to the first task in the list (forms a circular list).
-
-*/
-
-struct SilcTaskStruct {
-  int fd;
-  struct timeval timeout;
-  void *context;
-  SilcTaskCallback callback;
-  bool valid;
-  int priority;
-  int iomask;
-
-  struct SilcTaskStruct *next;
-  struct SilcTaskStruct *prev;
-};
-
-/* 
-   SILC Task types.
-
-   SILC has three types of tasks, non-timeout tasks (tasks that perform
-   over file descriptors), timeout tasks and generic tasks (tasks that apply
-   to every file descriptor). This type is sent as argument for the 
-   task registering function.
-
-*/
-typedef enum {
-  SILC_TASK_FD,
-  SILC_TASK_TIMEOUT,
-  SILC_TASK_GENERIC,
-} SilcTaskType;
-
-/* 
-   SILC Task priorities.
-
-   Following description of the priorities uses timeout tasks as example
-   how the priority behaves. However, non-timeout tasks behaves same as
-   timeout tasks with following priorities.
-
-   SILC_TASK_PRI_LOW
-
-       Lowest priority. The task is scheduled to run after its timeout
-       has expired only and only when every other task with higher priority 
-       has already been run. For non-timeout tasks this priority behaves
-       same way. Life is not fair for tasks with this priority.
-
-   SILC_TASK_PRI_NORMAL
-
-       Normal priority that is used mostly in Silc. This is priority that
-       should always be used unless you specificly need some other priority.
-       The scheduler will run this task as soon as its timeout has expired.
-       For non-timeout tasks this priority behaves same way. Tasks are run 
-       in FIFO (First-In-First-Out) order.
-
-*/
-typedef enum {
-  SILC_TASK_PRI_LOW,
-  SILC_TASK_PRI_NORMAL,
-} SilcTaskPriority;
-
-/* 
-   SILC Task Queue object. 
-   
-   Usually there are three task queues in SILC. Tasks with timeouts
-   has their own queue, tasks without timeout has one as well and generic
-   tasks has their own also. Scheduler has timeout queue hooks and 
-   non-timeout queue hooks in the scheduler and it does not check for 
-   timeouts in non-timeout hooks and vice versa, respectively. Ie. Register 
-   timeout queues to their own SilcTaskQueue pointer and non-timeout queues 
-   to their own pointer. 
-
-   Generic tasks, mentioned earlier, has their own task queue. These tasks 
-   are non-timeout tasks and they apply to all file descriptors, except to 
-   those that have explicitly registered a non-timeout task. These tasks
-   are there to make it simpler and faster to execute common code that
-   applies to all connections. These are, for example, receiving packets
-   from network and sending packets to network. It doesn't make much sense
-   to register a task that receives a packet from network to every connection
-   when you can have one task that applies to all connections. This is what
-   generic tasks are for. Generic tasks are not bound to any specific file
-   descriptor, however, the correct file descriptor must be passed as
-   argument to task registering function.
-
-   Short description of the field following:
-
-   SilcSchedule schedule
-
-       A back pointer to the scheduler.
-
-   SilcTask task
-
-       Pointer to the current (first) task in the queue.
-
-   int valid
-
-       Marks for validity of the queue. If the task queue is not valid 
-       scheduler will skip it. This is boolean value.
-
-   struct timeval timeout
-
-       Timeout when earliest some tasks in this queue should expire. The
-       value of this timeout is updated automatically by schedule. This 
-       is used only and only if this queue is a timeout queue. For normal
-       task queue this is not defined. This is meant only for internal
-       use and it should be considered to be read-only field.
-
-*/
-
-struct SilcTaskQueueStruct {
-  SilcSchedule schedule;
-  SilcTask task;
-  int valid;
-  struct timeval timeout;
-  SILC_MUTEX_DEFINE(lock);
-};
-
-/* Marks for all tasks in a task queue. This can be passed to 
-   unregister_task function to cancel all tasks at once. */
-#define SILC_ALL_TASKS ((SilcTask)1)
-
-/* Marks for all task queues. This can be passed to 
-   silc_task_queue_unregister function to cancel all task queues at once. */
-#define SILC_ALL_TASK_QUEUES ((SilcTaskQueue)1)
-
-/* Silc Task event types. One of these are passed to the task callback
-   function from the schedule. These values are also masked into a task
-   so that scheduler knows for what kind of I/O it needs to perform
-   for that task. */
-#define SILC_TASK_READ 0
-#define SILC_TASK_WRITE 1
-
-/* Macros */
-
-/* Generic macro to define task callback functions. This defines a function
-   with name 'func' as a task callback function. */
-#define SILC_TASK_CALLBACK(func) \
-static void func(void *qptr, int type, void *context, int fd)
-#define SILC_TASK_CALLBACK_GLOBAL(func) \
-void func(void *qptr, int type, void *context, int fd)
-
-/* Prototypes */
-void silc_task_queue_alloc(SilcSchedule schedule, SilcTaskQueue *queue, 
-                          bool valid);
-void silc_task_queue_free(SilcTaskQueue queue);
-void silc_task_queue_wakeup(SilcTaskQueue queue);
-SilcTask silc_task_register(SilcTaskQueue queue, int fd, 
-                           SilcTaskCallback cb, void *context, 
-                           long seconds, long useconds, 
-                           SilcTaskType type, 
-                           SilcTaskPriority priority);
-void silc_task_unregister(SilcTaskQueue queue, SilcTask task);
-void silc_task_unregister_by_fd(SilcTaskQueue queue, int fd);
-void silc_task_unregister_by_callback(SilcTaskQueue queue, 
-                                     SilcTaskCallback callback);
-void silc_task_unregister_by_context(SilcTaskQueue queue, void *context);
-void silc_task_set_iotype(SilcTask task, int type);
-void silc_task_reset_iotype(SilcTask task, int type);
-
-#endif
index 4c70827a5a290eaf4f3d93100b5a867885856139..78a366a04c6baf3c54d76aaeab7767ae4b898a4c 100644 (file)
 /* $Id$ */
 
 #include "silcincludes.h"
+#include "silcschedule_i.h"
 
 /* Calls normal select() system call. */
 
-int silc_select(int n, fd_set *readfds, fd_set *writefds,
-               fd_set *exceptfds, struct timeval *timeout)
+int silc_select(SilcScheduleFd fds, uint32 fds_count, struct timeval *timeout)
 {
-  return select(n, readfds, writefds, exceptfds, timeout);
+  fd_set in, out;
+  int ret, i, max_fd = 0;
+
+  FD_ZERO(&in);
+  FD_ZERO(&out);
+
+  for (i = 0; i < fds_count; i++) {
+    if (!fds[i].events)
+      continue;
+
+    if (fds[i].fd > max_fd)
+      max_fd = fds[i].fd;
+
+    if (fds[i].events & SILC_TASK_READ)
+      FD_SET(fds[i].fd, &in);
+    if (fds[i].events & SILC_TASK_WRITE)
+      FD_SET(fds[i].fd, &out);
+
+    fds[i].revents = 0;
+  }
+
+  ret = select(max_fd + 1, &in, &out, NULL, timeout);
+  if (ret <= 0)
+    return ret;
+
+  for (i = 0; i < fds_count; i++) {
+    if (!fds[i].events)
+      continue;
+
+    if (FD_ISSET(fds[i].fd, &in))
+      fds[i].revents |= SILC_TASK_READ;
+    if (FD_ISSET(fds[i].fd, &out))
+      fds[i].revents |= SILC_TASK_WRITE;
+  }
+
+  return ret;
 }
 
 #ifdef SILC_THREADS
@@ -54,7 +89,7 @@ SILC_TASK_CALLBACK(silc_schedule_wakeup_cb)
    It is quaranteed that the scheduler will automatically free any
    registered tasks in this queue. This is system specific routine. */
 
-void *silc_schedule_wakeup_init(void *queue)
+void *silc_schedule_wakeup_init(SilcSchedule schedule)
 {
 #ifdef SILC_THREADS
   SilcUnixWakeup wakeup;
@@ -66,10 +101,11 @@ void *silc_schedule_wakeup_init(void *queue)
     return NULL;
   }
 
-  wakeup->wakeup_task = silc_task_register(queue, wakeup->wakeup_pipe[0],
-                                          silc_schedule_wakeup_cb, wakeup,
-                                          0, 0, SILC_TASK_FD, 
-                                          SILC_TASK_PRI_NORMAL);
+  wakeup->wakeup_task = 
+    silc_schedule_task_add(schedule, wakeup->wakeup_pipe[0],
+                          silc_schedule_wakeup_cb, wakeup,
+                          0, 0, SILC_TASK_FD, 
+                          SILC_TASK_PRI_NORMAL);
   if (!wakeup->wakeup_task) {
     close(wakeup->wakeup_pipe[0]);
     close(wakeup->wakeup_pipe[1]);
index 20f9c5a569f276fc90db1df6a23acc7eb6b70079..693cbfc8d6ab3e607615f16e62dad94f3a8c178d 100644 (file)
@@ -190,7 +190,7 @@ SILC_TASK_CALLBACK(silc_schedule_wakeup_cb)
    It is guaranteed that the scheduler will automatically free any
    registered tasks in this queue. This is system specific routine. */
 
-void *silc_schedule_wakeup_init(void *queue)
+void *silc_schedule_wakeup_init(SilcSchedule schedule)
 {
 #ifdef SILC_THREADS
   SilcWin32Wakeup wakeup;
@@ -203,10 +203,11 @@ void *silc_schedule_wakeup_init(void *queue)
     return NULL;
   }
 
-  wakeup->wakeup_task = silc_task_register(queue, (int)wakeup->wakeup_sema,
-                                          silc_schedule_wakeup_cb, wakeup,
-                                          0, 0, SILC_TASK_FD, 
-                                          SILC_TASK_PRI_NORMAL);
+  wakeup->wakeup_task = 
+    silc_schedule_task_add(schedule, (int)wakeup->wakeup_sema,
+                          silc_schedule_wakeup_cb, wakeup,
+                          0, 0, SILC_TASK_FD, 
+                          SILC_TASK_PRI_NORMAL);
   if (!wakeup->wakeup_task) {
     CloseHandle(wakeup->wakeup_sema);
     silc_free(wakeup);