[PATCH 11/13] reds: Make VDIPortState a GObject

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Christophe Fergeau <cfergeau@xxxxxxxxxx>

This inherits from RedCharDevice.

Signed-off-by: Christophe Fergeau <cfergeau@xxxxxxxxxx>
---
 server/reds-private.h |   2 +-
 server/reds.c         | 242 ++++++++++++++++++++++++++++++++------------------
 2 files changed, 157 insertions(+), 87 deletions(-)

diff --git a/server/reds-private.h b/server/reds-private.h
index 8842aad..b3dac6d 100644
--- a/server/reds-private.h
+++ b/server/reds-private.h
@@ -88,7 +88,7 @@ typedef struct RedSSLParameters {
     char ciphersuite[256];
 } RedSSLParameters;
 
-typedef struct VDIPortState VDIPortState;
+typedef struct RedCharDeviceVDIPort VDIPortState;
 
 struct RedsState {
     int listen_socket;
diff --git a/server/reds.c b/server/reds.c
index 4ef701b..a8cc5da 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -181,8 +181,8 @@ enum {
     VDI_PORT_READ_STATE_READ_DATA,
 };
 
-struct VDIPortStatePrivate {
-    SpiceCharDeviceState *base;
+struct RedCharDeviceVDIPortPrivate {
+    gboolean agent_attached;
     uint32_t plug_generation;
     int client_agent_started;
 
@@ -206,10 +206,6 @@ struct VDIPortStatePrivate {
                                        before agent is attached */
 };
 
-struct VDIPortState {
-    struct VDIPortStatePrivate priv[1];
-};
-
 /* messages that are addressed to the agent and are created in the server */
 typedef struct __attribute__ ((__packed__)) VDInternalBuf {
     VDIChunkHeader chunk_header;
@@ -220,6 +216,37 @@ typedef struct __attribute__ ((__packed__)) VDInternalBuf {
     u;
 } VDInternalBuf;
 
+#define RED_TYPE_CHAR_DEVICE_VDIPORT red_char_device_vdi_port_get_type()
+
+#define RED_CHAR_DEVICE_VDIPORT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), RED_TYPE_CHAR_DEVICE_VDIPORT, RedCharDeviceVDIPort))
+#define RED_CHAR_DEVICE_VDIPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), RED_TYPE_CHAR_DEVICE_VDIPORT, RedCharDeviceVDIPortClass))
+#define RED_IS_CHAR_DEVICE_VDIPORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), RED_TYPE_CHAR_DEVICE_VDIPORT))
+#define RED_IS_CHAR_DEVICE_VDIPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), RED_TYPE_CHAR_DEVICE_VDIPORT))
+#define RED_CHAR_DEVICE_VDIPORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), RED_TYPE_CHAR_DEVICE_VDIPORT, RedCharDeviceVDIPortClass))
+
+typedef struct RedCharDeviceVDIPort RedCharDeviceVDIPort;
+typedef struct RedCharDeviceVDIPortClass RedCharDeviceVDIPortClass;
+typedef struct RedCharDeviceVDIPortPrivate RedCharDeviceVDIPortPrivate;
+
+struct RedCharDeviceVDIPort
+{
+    RedCharDevice parent;
+
+    RedCharDeviceVDIPortPrivate *priv;
+};
+
+struct RedCharDeviceVDIPortClass
+{
+    RedCharDeviceClass parent_class;
+};
+
+static GType red_char_device_vdi_port_get_type(void) G_GNUC_CONST;
+
+G_DEFINE_TYPE(RedCharDeviceVDIPort, red_char_device_vdi_port, RED_TYPE_CHAR_DEVICE)
+
+#define RED_CHAR_DEVICE_VDIPORT_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RED_TYPE_CHAR_DEVICE_VDIPORT, RedCharDeviceVDIPortPrivate))
+
+static RedCharDeviceVDIPort *red_char_device_vdi_port_new(RedsState *reds);
 
 static void migrate_timeout(void *opaque);
 static RedsMigTargetClient* reds_mig_target_client_find(RedsState *reds, RedClient *client);
@@ -489,10 +516,9 @@ static void reds_reset_vdp(RedsState *reds)
      */
     if (red_channel_test_remote_cap(&reds->main_channel->base,
                                     SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS)) {
-        spice_char_device_state_destroy(state->priv->base);
-        state->priv->base = NULL;
+        state->priv->agent_attached = FALSE;
     } else {
-        spice_char_device_reset(state->priv->base);
+        spice_char_device_reset(RED_CHAR_DEVICE(state));
     }
 
     sif = spice_char_device_get_interface(reds->vdagent);
@@ -540,11 +566,11 @@ void reds_client_disconnect(RedsState *reds, RedClient *client)
         reds_mig_remove_wait_disconnect_client(reds, client);
     }
 
-    if (reds->agent_state->priv->base) {
+    if (reds->agent_state->priv->agent_attached) {
         /* note that vdagent might be NULL, if the vdagent was once
          * up and than was removed */
-        if (spice_char_device_client_exists(reds->agent_state->priv->base, client)) {
-            spice_char_device_client_remove(reds->agent_state->priv->base, client);
+        if (spice_char_device_client_exists(RED_CHAR_DEVICE(reds->agent_state), client)) {
+            spice_char_device_client_remove(RED_CHAR_DEVICE(reds->agent_state), client);
         }
     }
 
@@ -556,14 +582,14 @@ void reds_client_disconnect(RedsState *reds, RedClient *client)
    // if we are in the middle of one from another client)
     if (reds->num_clients == 0) {
         /* Let the agent know the client is disconnected */
-        if (reds->agent_state->priv->base) {
+        if (reds->agent_state->priv->agent_attached) {
             SpiceCharDeviceWriteBuffer *char_dev_buf;
             VDInternalBuf *internal_buf;
             uint32_t total_msg_size;
 
             total_msg_size = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage);
             char_dev_buf = spice_char_device_write_buffer_get_server_no_token(
-                               reds->agent_state->priv->base, total_msg_size);
+                               RED_CHAR_DEVICE(reds->agent_state), total_msg_size);
             char_dev_buf->buf_used = total_msg_size;
             internal_buf = (VDInternalBuf *)char_dev_buf->buf;
             internal_buf->chunk_header.port = VDP_SERVER_PORT;
@@ -573,7 +599,7 @@ void reds_client_disconnect(RedsState *reds, RedClient *client)
             internal_buf->header.opaque = 0;
             internal_buf->header.size = 0;
 
-            spice_char_device_write_buffer_add(reds->agent_state->priv->base,
+            spice_char_device_write_buffer_add(RED_CHAR_DEVICE(reds->agent_state),
                                                char_dev_buf);
         }
 
@@ -753,8 +779,8 @@ static void vdi_port_read_buf_unref(VDIReadBuf *buf)
         ring was empty. So we call it again so it can complete its work if
         necessary. Note that since we can be called from spice_char_device_wakeup
         this can cause recursion, but we have protection for that */
-        if (buf->state->priv->base) {
-            spice_char_device_wakeup(buf->state->priv->base);
+        if (buf->state->priv->agent_attached) {
+            spice_char_device_wakeup(RED_CHAR_DEVICE(buf->state));
         }
     }
 }
@@ -894,13 +920,13 @@ void reds_handle_agent_mouse_event(RedsState *reds, const VDAgentMouseState *mou
     VDInternalBuf *internal_buf;
     uint32_t total_msg_size;
 
-    if (!reds->inputs_channel || !reds->agent_state->priv->base) {
+    if (!reds->inputs_channel || !reds->agent_state->priv->agent_attached) {
         return;
     }
 
     total_msg_size = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage) +
                      sizeof(VDAgentMouseState);
-    char_dev_buf = spice_char_device_write_buffer_get(reds->agent_state->priv->base,
+    char_dev_buf = spice_char_device_write_buffer_get(RED_CHAR_DEVICE(reds->agent_state),
                                                       NULL,
                                                       total_msg_size);
 
@@ -921,7 +947,7 @@ void reds_handle_agent_mouse_event(RedsState *reds, const VDAgentMouseState *mou
     internal_buf->u.mouse_state = *mouse_state;
 
     char_dev_buf->buf_used = total_msg_size;
-    spice_char_device_write_buffer_add(reds->agent_state->priv->base, char_dev_buf);
+    spice_char_device_write_buffer_add(RED_CHAR_DEVICE(reds->agent_state), char_dev_buf);
 }
 
 int reds_get_n_channels(RedsState *reds)
@@ -978,7 +1004,7 @@ void reds_fill_channels(RedsState *reds, SpiceMsgChannels *channels_info)
 
 void reds_on_main_agent_start(RedsState *reds, MainChannelClient *mcc, uint32_t num_tokens)
 {
-    SpiceCharDeviceState *dev_state = reds->agent_state->priv->base;
+    SpiceCharDeviceState *dev_state = RED_CHAR_DEVICE(reds->agent_state);
     RedChannelClient *rcc;
 
     if (!reds->vdagent) {
@@ -1051,7 +1077,7 @@ uint8_t *reds_get_agent_data_buffer(RedsState *reds, MainChannelClient *mcc, siz
 
     spice_assert(dev_state->priv->recv_from_client_buf == NULL);
     client = main_channel_client_get_base(mcc)->client;
-    dev_state->priv->recv_from_client_buf = spice_char_device_write_buffer_get(dev_state->priv->base,
+    dev_state->priv->recv_from_client_buf = spice_char_device_write_buffer_get(RED_CHAR_DEVICE(dev_state),
                                                                                client,
                                                                                size + sizeof(VDIChunkHeader));
     dev_state->priv->recv_from_client_buf_pushed = FALSE;
@@ -1069,7 +1095,7 @@ void reds_release_agent_data_buffer(RedsState *reds, uint8_t *buf)
 
     spice_assert(buf == dev_state->priv->recv_from_client_buf->buf + sizeof(VDIChunkHeader));
     if (!dev_state->priv->recv_from_client_buf_pushed) {
-        spice_char_device_write_buffer_release(reds->agent_state->priv->base,
+        spice_char_device_write_buffer_release(RED_CHAR_DEVICE(reds->agent_state),
                                                dev_state->priv->recv_from_client_buf);
     }
     dev_state->priv->recv_from_client_buf = NULL;
@@ -1141,7 +1167,7 @@ void reds_on_main_agent_data(RedsState *reds, MainChannelClient *mcc, void *mess
     dev_state->priv->recv_from_client_buf->buf_used = sizeof(VDIChunkHeader) + size;
 
     dev_state->priv->recv_from_client_buf_pushed = TRUE;
-    spice_char_device_write_buffer_add(reds->agent_state->priv->base, dev_state->priv->recv_from_client_buf);
+    spice_char_device_write_buffer_add(RED_CHAR_DEVICE(reds->agent_state), dev_state->priv->recv_from_client_buf);
 }
 
 void reds_on_main_migrate_connected(RedsState *reds, int seamless)
@@ -1236,7 +1262,7 @@ void reds_marshall_migrate_data(RedsState *reds, SpiceMarshaller *m)
            is set to FALSE when the agent is disconnected and
            there is no need to track the client tokens
            (see reds_reset_vdp) */
-        spice_assert(!agent_state->priv->base);
+        spice_assert(!agent_state->priv->agent_attached);
         spice_char_device_state_migrate_data_marshall_empty(m);
         null_agent_mig_data = spice_marshaller_reserve_space(m,
                                                              sizeof(SpiceMigrateDataMain) -
@@ -1247,7 +1273,7 @@ void reds_marshall_migrate_data(RedsState *reds, SpiceMarshaller *m)
         return;
     }
 
-    spice_char_device_state_migrate_data_marshall(reds->agent_state->priv->base, m);
+    spice_char_device_state_migrate_data_marshall(RED_CHAR_DEVICE(reds->agent_state), m);
     spice_marshaller_add_uint8(m, reds->agent_state->priv->client_agent_started);
 
     mig_data.agent2client.chunk_header = agent_state->priv->vdi_chunk_header;
@@ -1367,7 +1393,7 @@ static int reds_agent_state_restore(RedsState *reds, SpiceMigrateDataMain *mig_d
                 agent_state->priv->read_filter.discard_all,
                 agent_state->priv->read_filter.msg_data_to_read,
                  agent_state->priv->read_filter.result);
-    return spice_char_device_state_restore(agent_state->priv->base, &mig_data->agent_base);
+    return spice_char_device_state_restore(RED_CHAR_DEVICE(agent_state), &mig_data->agent_base);
 }
 
 /*
@@ -1390,7 +1416,7 @@ int reds_handle_migrate_data(RedsState *reds, MainChannelClient *mcc,
         reds_send_mm_time(reds);
     }
     if (mig_data->agent_base.connected) {
-        if (agent_state->priv->base) { // agent was attached before migration data has arrived
+        if (agent_state->priv->agent_attached) { // agent was attached before migration data has arrived
             if (!reds->vdagent) {
                 spice_assert(agent_state->priv->plug_generation > 0);
                 main_channel_push_agent_disconnected(reds->main_channel);
@@ -1416,7 +1442,7 @@ int reds_handle_migrate_data(RedsState *reds, MainChannelClient *mcc,
         spice_debug("agent was not attached on the source host");
         if (reds->vdagent) {
             /* spice_char_device_client_remove disables waiting for migration data */
-            spice_char_device_client_remove(agent_state->priv->base,
+            spice_char_device_client_remove(RED_CHAR_DEVICE(agent_state),
                                             main_channel_client_get_base(mcc)->client);
             main_channel_push_agent_connected(reds->main_channel);
         }
@@ -3029,25 +3055,12 @@ static SpiceCharDeviceState *attach_to_red_agent(RedsState *reds, SpiceCharDevic
 {
     VDIPortState *state = reds->agent_state;
     SpiceCharDeviceInterface *sif;
-    SpiceCharDeviceCallbacks char_dev_state_cbs;
-
-    if (!state->priv->base) {
-        char_dev_state_cbs.read_one_msg_from_device = vdi_port_read_one_msg_from_device;
-        char_dev_state_cbs.ref_msg_to_client = vdi_port_ref_msg_to_client;
-        char_dev_state_cbs.unref_msg_to_client = vdi_port_unref_msg_to_client;
-        char_dev_state_cbs.send_msg_to_client = vdi_port_send_msg_to_client;
-        char_dev_state_cbs.send_tokens_to_client = vdi_port_send_tokens_to_client;
-        char_dev_state_cbs.remove_client = vdi_port_remove_client;
-        char_dev_state_cbs.on_free_self_token = vdi_port_on_free_self_token;
-
-        state->priv->base = spice_char_device_state_create(sin,
-                                                     reds,
-                                                     REDS_TOKENS_TO_SEND,
-                                                     REDS_NUM_INTERNAL_AGENT_MESSAGES,
-                                                     &char_dev_state_cbs,
-                                                     reds);
+
+    if (state->priv->agent_attached) {
+        spice_char_device_state_reset_dev_instance(RED_CHAR_DEVICE(state), sin);
     } else {
-        spice_char_device_state_reset_dev_instance(state->priv->base, sin);
+        state->priv->agent_attached = TRUE;
+        g_object_set(G_OBJECT(state), "sin", sin, NULL);
     }
 
     reds->vdagent = sin;
@@ -3059,13 +3072,13 @@ static SpiceCharDeviceState *attach_to_red_agent(RedsState *reds, SpiceCharDevic
     }
 
     if (!reds_main_channel_connected(reds)) {
-        return state->priv->base;
+        return RED_CHAR_DEVICE(state);
     }
 
     state->priv->read_filter.discard_all = FALSE;
-    reds->agent_state->priv->plug_generation++;
+    state->priv->plug_generation++;
 
-    if (reds->agent_state->priv->mig_data ||
+    if (state->priv->mig_data ||
         red_channel_is_waiting_for_migrate_data(&reds->main_channel->base)) {
         /* Migration in progress (code is running on the destination host):
          * 1.  Add the client to spice char device, if it was not already added.
@@ -3074,10 +3087,10 @@ static SpiceCharDeviceState *attach_to_red_agent(RedsState *reds, SpiceCharDevic
          * 2.b If this happens second ==> we already have spice migrate data
          *     then restore state
          */
-        if (!spice_char_device_client_exists(reds->agent_state->priv->base, reds_get_client(reds))) {
+        if (!spice_char_device_client_exists(RED_CHAR_DEVICE(state), reds_get_client(reds))) {
             int client_added;
 
-            client_added = spice_char_device_client_add(reds->agent_state->priv->base,
+            client_added = spice_char_device_client_add(RED_CHAR_DEVICE(state),
                                                         reds_get_client(reds),
                                                         TRUE, /* flow control */
                                                         REDS_VDI_PORT_NUM_RECEIVE_BUFFS,
@@ -3091,12 +3104,12 @@ static SpiceCharDeviceState *attach_to_red_agent(RedsState *reds, SpiceCharDevic
             }
         }
 
-        if (reds->agent_state->priv->mig_data) {
+        if (state->priv->mig_data) {
             spice_debug("restoring state from stored migration data");
-            spice_assert(reds->agent_state->priv->plug_generation == 1);
-            reds_agent_state_restore(reds, reds->agent_state->priv->mig_data);
-            free(reds->agent_state->priv->mig_data);
-            reds->agent_state->priv->mig_data = NULL;
+            spice_assert(state->priv->plug_generation == 1);
+            reds_agent_state_restore(reds, state->priv->mig_data);
+            free(state->priv->mig_data);
+            state->priv->mig_data = NULL;
         }
         else {
             spice_debug("waiting for migration data");
@@ -3107,7 +3120,7 @@ static SpiceCharDeviceState *attach_to_red_agent(RedsState *reds, SpiceCharDevic
         main_channel_push_agent_connected(reds->main_channel);
     }
 
-    return state->priv->base;
+    return RED_CHAR_DEVICE(state);
 }
 
 SPICE_GNUC_VISIBLE void spice_server_char_device_wakeup(SpiceCharDeviceInstance* sin)
@@ -3364,33 +3377,6 @@ SPICE_GNUC_VISIBLE int spice_server_remove_interface(SpiceBaseInstance *sin)
     return 0;
 }
 
-static void reds_init_vd_agent_resources(RedsState *reds)
-{
-    VDIPortState *state;
-    int i;
-
-    reds->agent_state = g_new0(VDIPortState, 1);
-    state = reds->agent_state;
-    ring_init(&state->priv->read_bufs);
-    agent_msg_filter_init(&state->priv->write_filter, reds->agent_copypaste,
-                          reds->agent_file_xfer,
-                          reds_use_client_monitors_config(reds), TRUE);
-    agent_msg_filter_init(&state->priv->read_filter, reds->agent_copypaste,
-                          reds->agent_file_xfer,
-                          reds_use_client_monitors_config(reds), TRUE);
-
-    state->priv->read_state = VDI_PORT_READ_STATE_READ_HEADER;
-    state->priv->receive_pos = (uint8_t *)&state->priv->vdi_chunk_header;
-    state->priv->receive_len = sizeof(state->priv->vdi_chunk_header);
-
-    for (i = 0; i < REDS_VDI_PORT_NUM_RECEIVE_BUFFS; i++) {
-        VDIReadBuf *buf = spice_new0(VDIReadBuf, 1);
-        buf->state = state;
-        ring_item_init(&buf->link);
-        ring_add(&reds->agent_state->priv->read_bufs, &buf->link);
-    }
-}
-
 static int do_spice_init(RedsState *reds, SpiceCoreInterface *core_interface)
 {
     static gboolean first = TRUE;
@@ -3404,7 +3390,7 @@ static int do_spice_init(RedsState *reds, SpiceCoreInterface *core_interface)
     reds->core = &core_interface_adapter;
     reds->listen_socket = -1;
     reds->secure_listen_socket = -1;
-    reds_init_vd_agent_resources(reds);
+    reds->agent_state = red_char_device_vdi_port_new(reds);
     ring_init(&reds->clients);
     reds->num_clients = 0;
     reds->main_dispatcher = main_dispatcher_new(reds, reds->core);
@@ -4297,3 +4283,87 @@ MainDispatcher* reds_get_main_dispatcher(RedsState *reds)
 {
     return reds->main_dispatcher;
 }
+
+static void red_char_device_vdi_port_constructed(GObject *object)
+{
+    RedCharDeviceVDIPort *dev = RED_CHAR_DEVICE_VDIPORT(object);
+    RedsState *reds;
+
+    G_OBJECT_CLASS(red_char_device_vdi_port_parent_class)->constructed(object);
+
+    g_object_get(dev, "spice-server", &reds, NULL);
+
+    agent_msg_filter_init(&dev->priv->write_filter, reds->agent_copypaste,
+                          reds->agent_file_xfer,
+                          reds_use_client_monitors_config(reds),
+                          TRUE);
+    agent_msg_filter_init(&dev->priv->read_filter, reds->agent_copypaste,
+                          reds->agent_file_xfer,
+                          reds_use_client_monitors_config(reds),
+                          TRUE);
+}
+
+static void
+red_char_device_vdi_port_init(RedCharDeviceVDIPort *self)
+{
+    int i;
+
+    self->priv = RED_CHAR_DEVICE_VDIPORT_PRIVATE(self);
+
+    ring_init(&self->priv->read_bufs);
+
+    self->priv->read_state = VDI_PORT_READ_STATE_READ_HEADER;
+    self->priv->receive_pos = (uint8_t *)&self->priv->vdi_chunk_header;
+    self->priv->receive_len = sizeof(self->priv->vdi_chunk_header);
+
+    for (i = 0; i < REDS_VDI_PORT_NUM_RECEIVE_BUFFS; i++) {
+        VDIReadBuf *buf = spice_new0(VDIReadBuf, 1);
+        buf->state = self;
+        ring_item_init(&buf->link);
+        ring_add(&self->priv->read_bufs, &buf->link);
+    }
+}
+
+static void
+red_char_device_vdi_port_finalize(GObject *object)
+{
+    RedCharDeviceVDIPort *dev = RED_CHAR_DEVICE_VDIPORT(object);
+
+   free(dev->priv->mig_data);
+   /* FIXME: need to free the VDIReadBuf allocated previously */
+}
+
+static void
+red_char_device_vdi_port_class_init(RedCharDeviceVDIPortClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+    g_type_class_add_private(klass, sizeof (RedCharDeviceVDIPortPrivate));
+
+    object_class->finalize = red_char_device_vdi_port_finalize;
+    object_class->constructed = red_char_device_vdi_port_constructed;
+}
+
+static RedCharDeviceVDIPort *red_char_device_vdi_port_new(RedsState *reds)
+{
+    RedCharDevice *char_dev;
+    SpiceCharDeviceCallbacks char_dev_cbs = {
+        .read_one_msg_from_device = vdi_port_read_one_msg_from_device,
+        .ref_msg_to_client = vdi_port_ref_msg_to_client,
+        .unref_msg_to_client = vdi_port_unref_msg_to_client,
+        .send_msg_to_client = vdi_port_send_msg_to_client,
+        .send_tokens_to_client = vdi_port_send_tokens_to_client,
+        .remove_client = vdi_port_remove_client,
+        .on_free_self_token = vdi_port_on_free_self_token,
+    };
+
+    char_dev = g_object_new(RED_TYPE_CHAR_DEVICE_VDIPORT,
+                            "spice-server", reds,
+                            "client-tokens-interval", REDS_TOKENS_TO_SEND,
+                            "self-tokens", REDS_NUM_INTERNAL_AGENT_MESSAGES,
+                            NULL);
+
+    red_char_device_set_callbacks(RED_CHAR_DEVICE(char_dev),
+                                  &char_dev_cbs, reds);
+    return RED_CHAR_DEVICE_VDIPORT(char_dev);
+}
-- 
2.5.5

_______________________________________________
Spice-devel mailing list
Spice-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/spice-devel




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]     [Monitors]