Esempio n. 1
0
static gpointer
test_g_mutex_thread (gpointer data)
{
  g_assert (GPOINTER_TO_INT (data) == 42);
  g_assert (g_mutex_trylock (&test_g_mutex_mutex) == FALSE);
  g_assert (G_TRYLOCK (test_g_mutex) == FALSE);
  test_g_mutex_thread_ready = TRUE;
  g_mutex_lock (&test_g_mutex_mutex);
  g_assert (test_g_mutex_int == 42);
  g_mutex_unlock (&test_g_mutex_mutex);

  return GINT_TO_POINTER (41);
}
Esempio n. 2
0
static void
test_g_mutex (void)
{
  GThread *thread;

  g_assert (g_mutex_trylock (&test_g_mutex_mutex));
  g_assert (G_TRYLOCK (test_g_mutex));
  test_g_mutex_thread_ready = FALSE;
  thread = g_thread_create (test_g_mutex_thread, GINT_TO_POINTER (42),
			    TRUE, NULL);
  /* This busy wait is only for testing purposes and not an example of
   * good code!*/
  while (!test_g_mutex_thread_ready)
    g_usleep (G_USEC_PER_SEC / 5);
  test_g_mutex_int = 42;
  G_UNLOCK (test_g_mutex);
  g_mutex_unlock (&test_g_mutex_mutex);
  g_assert (GPOINTER_TO_INT (g_thread_join (thread)) == 41);
}
Esempio n. 3
0
static hb_buffer_t *
acquire_buffer (gboolean *free_buffer)
{
  hb_buffer_t *buffer;

  if (G_LIKELY (G_TRYLOCK (cached_buffer)))
    {
      if (G_UNLIKELY (!cached_buffer))
	cached_buffer = hb_buffer_create ();

      buffer = cached_buffer;
      *free_buffer = FALSE;
    }
  else
    {
      buffer = hb_buffer_create ();
      *free_buffer = TRUE;
    }

  return buffer;
}
Esempio n. 4
0
static gboolean
process_cm_event (GIOChannel *source, GIOCondition condition, gpointer data)
{
    // Right now, we don't need 'source' and 'condition'
    // Tell the compiler to ignore them by (void)-ing them
    (void) source;
    (void) condition;

    g_debug ("CM event handler triggered");
    if (!G_TRYLOCK (connection_handling)) {
        // Unsafe to handle connection management right now.
        // Wait for next dispatch.
        g_debug ("Connection handling is busy. Waiting for next dispatch");
        return TRUE;
    }

    KiroServerPrivate *priv = (KiroServerPrivate *)data;
    struct rdma_cm_event *active_event;

    if (0 <= rdma_get_cm_event (priv->ec, &active_event)) {
        struct rdma_cm_event *ev = g_try_malloc (sizeof (*active_event));

        if (!ev) {
            g_critical ("Unable to allocate memory for Event handling!");
            rdma_ack_cm_event (active_event);
            goto exit;
        }

        memcpy (ev, active_event, sizeof (*active_event));
        rdma_ack_cm_event (active_event);

        if (ev->event == RDMA_CM_EVENT_CONNECT_REQUEST) {
            if (TRUE == priv->close_signal) {
                //Main thread has signalled shutdown!
                //Don't connect this client any more.
                //Sorry mate!
                rdma_reject (ev->id, NULL, 0);
                goto exit;
            }

            do {
                g_debug ("Got connection request from client");
                struct kiro_client_connection *cc = (struct kiro_client_connection *)g_try_malloc (sizeof (struct kiro_client_connection));
                if (!cc) {
                    errno = ENOMEM;
                    rdma_reject (ev->id, NULL, 0);
                    goto fail;
                }

                if (connect_client (ev->id))
                    goto fail;

                // Post a welcoming "Receive" for handshaking
                if (grant_client_access (ev->id, priv->mem, priv->mem_size, KIRO_ACK_RDMA))
                    goto fail;

                ibv_req_notify_cq (ev->id->recv_cq, 0); // Make the respective Queue push events onto the channel

                // Connection set-up successfully! (Server)
                // ctx was created by 'welcome_client'
                struct kiro_connection_context *ctx = (struct kiro_connection_context *) (ev->id->context);
                ctx->identifier = priv->next_client_id++;
                ctx->container = cc; // Make the connection aware of its container

                // Fill the client connection container. Also create a
                // g_io_channel wrapper for the new clients receive queue event
                // channel and add a main_loop watch to it.
                cc->id = ctx->identifier;
                cc->conn = ev->id;
                cc->rcv_ec = g_io_channel_unix_new (ev->id->recv_cq_channel->fd);
                priv->clients = g_list_append (priv->clients, (gpointer)cc);
                GList *client = g_list_find (priv->clients, (gpointer)cc);
                if (!client->data || client->data != cc) {
                    g_critical ("Could not add client to list");
                    goto fail;
                }

                cc->source_id = g_io_add_watch (cc->rcv_ec, G_IO_IN | G_IO_PRI, process_rdma_event, (gpointer)client);
                g_io_channel_unref (cc->rcv_ec); // main_loop now holds a reference. We don't need ours any more

                g_debug ("Client connection assigned with ID %u", ctx->identifier);
                g_debug ("Currently %u clients in total are connected", g_list_length (priv->clients));
                break;

                fail:
                    g_warning ("Failed to accept client connection: %s", strerror (errno));
                    if (errno == EINVAL)
                        g_message ("This might happen if the client pulls back the connection request before the server can handle it.");

            } while(0);
        }
        else if (ev->event == RDMA_CM_EVENT_DISCONNECTED) {
            struct kiro_connection_context *ctx = (struct kiro_connection_context *) (ev->id->context);
            if (!ctx->container) {
                g_debug ("Got disconnect request from unknown client");
                goto exit;
            }

            GList *client = g_list_find (priv->clients, (gconstpointer) ctx->container);

            if (client) {
                g_debug ("Got disconnect request from client ID %u", ctx->identifier);
                struct kiro_client_connection *cc = (struct kiro_client_connection *)ctx->container;
                g_source_remove (cc->source_id); // this also unrefs the GIOChannel of the source. Nice.
                priv->clients = g_list_delete_link (priv->clients, client);
                g_free (cc);
                ctx->container = NULL;
            }
            else
                g_debug ("Got disconnect request from unknown client");

            // Note:
            // The ProtectionDomain needs to be buffered and freed manually.
            // Each connecting client is attached with its own pd, which we
            // create manually. So we also need to clean it up manually.
            // This needs to be done AFTER the connection is brought down, so we
            // buffer the pointer to the pd and clean it up afterwards.
            struct ibv_pd *pd = ev->id->pd;
            kiro_destroy_connection (& (ev->id));
            g_free (pd);

            g_debug ("Connection closed successfully. %u connected clients remaining", g_list_length (priv->clients));
        }

exit:
        g_free (ev);
    }

    G_UNLOCK (connection_handling);
    g_debug ("CM event handling done");
    return TRUE;
}
Esempio n. 5
0
static gboolean
process_rdma_event (GIOChannel *source, GIOCondition condition, gpointer data)
{
    // Right now, we don't need 'source'
    // Tell the compiler to ignore it by (void)-ing it
    (void) source;

    if (!G_TRYLOCK (rdma_handling)) {
        g_debug ("RDMA handling will wait for the next dispatch.");
        return TRUE;
    }

    g_debug ("Got message on condition: %i", condition);
    void *payload = ((GList *)data)->data;
    struct kiro_client_connection *cc = (struct kiro_client_connection *)payload;
    struct ibv_wc wc;

    gint num_comp = ibv_poll_cq (cc->conn->recv_cq, 1, &wc);
    if (!num_comp) {
        g_critical ("RDMA event handling was triggered, but there is no completion on the queue");
        goto end_rmda_eh;
    }
    if (num_comp < 0) {
        g_critical ("Failure getting receive completion event from the queue: %s", strerror (errno));
        goto end_rmda_eh;
    }
    g_debug ("Got %i receive events from the queue", num_comp);
    void *cq_ctx;
    struct ibv_cq *cq;
    int err = ibv_get_cq_event (cc->conn->recv_cq_channel, &cq, &cq_ctx);
    if (!err)
        ibv_ack_cq_events (cq, 1);

    struct kiro_connection_context *ctx = (struct kiro_connection_context *)cc->conn->context;
    guint type = ((struct kiro_ctrl_msg *)ctx->cf_mr_recv->mem)->msg_type;
    g_debug ("Received a message from Client %u of type %u", cc->id, type);

    switch (type) {
        case KIRO_PING:
        {
            struct kiro_ctrl_msg *msg = (struct kiro_ctrl_msg *) (ctx->cf_mr_send->mem);
            msg->msg_type = KIRO_PONG;

            if (!send_msg (cc->conn, ctx->cf_mr_send)) {
                g_warning ("Failure while trying to post PONG send: %s", strerror (errno));
                goto done;
            }
            break;
        }
        case KIRO_ACK_RDMA:
        {
            g_debug ("ACK received");
            if (G_TRYLOCK (realloc_timeout)) {
                g_debug ("Client %i has ACKed the reallocation request", cc->id);
                GList *client = g_list_find (realloc_list, (gpointer)cc);
                if (client) {
                    realloc_list = g_list_remove_link (realloc_list, client);
                    if (cc->backup_mri->mr)
                        ibv_dereg_mr (cc->backup_mri->mr);
                    g_free (cc->backup_mri);
                    cc->backup_mri = NULL;
                    g_debug ("Client %i removed from realloc_list", cc->id);
                }
                G_UNLOCK (realloc_timeout);
            }
            break;
        }
        default:
            g_debug ("Message Type is unknow. Ignoring...");
    }

done:
    //Post a generic receive in order to stay responsive to any messages from
    //the client
    if (rdma_post_recv (cc->conn, cc->conn, ctx->cf_mr_recv->mem, ctx->cf_mr_recv->size, ctx->cf_mr_recv->mr)) {
        //TODO: Connection teardown in an event handler routine? Not a good
        //idea...
        g_critical ("Posting generic receive for event handling failed: %s", strerror (errno));
        kiro_destroy_connection_context (&ctx);
        rdma_destroy_ep (cc->conn);
        goto end_rmda_eh;
    }

    ibv_req_notify_cq (cc->conn->recv_cq, 0); // Make the respective Queue push events onto the channel

    g_debug ("Finished RDMA event handling");

end_rmda_eh:
    G_UNLOCK (rdma_handling);
    return TRUE;
}
Esempio n. 6
0
/*
 * Get mime-type info of the specified file (slow, but more accurate):
 * To determine the mime-type of the file, mime_type_get_by_filename() is
 * tried first.  If the mime-type couldn't be determined, the content of
 * the file will be checked, which is much more time-consuming.
 * If statbuf is not NULL, it will be used to determine if the file is a directory,
 * or if the file is an executable file; otherwise, the function will call stat()
 * to gather this info itself. So if you already have stat info of the file,
 * pass it to the function to prevent checking the file stat again.
 * If you have basename of the file, pass it to the function can improve the
 * efifciency, too. Otherwise, the function will try to get the basename of
 * the specified file again.
*/
const char* mime_type_get_by_file( const char* filepath, struct stat64* statbuf, const char* basename )
{
    const char* type;
    struct stat64 _statbuf;

    if( statbuf == NULL || G_UNLIKELY( S_ISLNK(statbuf->st_mode) ) )
    {
        statbuf = &_statbuf;
        if( stat64 ( filepath, statbuf ) == -1 )
            return XDG_MIME_TYPE_UNKNOWN;
    }

    if( S_ISDIR( statbuf->st_mode ) )
        return XDG_MIME_TYPE_DIRECTORY;

    if( basename == NULL )
    {
        basename = g_utf8_strrchr( filepath, -1, '/' );
        if( G_LIKELY( basename ) )
            ++basename;
        else
            basename = filepath;
    }

    if( G_LIKELY(basename) )
    {
        type = mime_type_get_by_filename( basename, statbuf );
        if( G_LIKELY( strcmp( type, XDG_MIME_TYPE_UNKNOWN ) ) )
            return type;
        type = NULL;
    }

    //sfm added check for fifo due to hang on one system with a particular pipe
    // - is this needed?
    if( G_LIKELY(statbuf->st_size > 0 && !S_ISFIFO( statbuf->st_mode ) ) )
    {
        int fd = -1;
        char* data;

        /* Open the file and map it into memory */
        fd = open ( filepath, O_RDONLY, 0 );
        if ( fd != -1 )
        {
            int len = mime_cache_max_extent < statbuf->st_size ?  mime_cache_max_extent : statbuf->st_size;
#ifdef HAVE_MMAP
            data = (char*) mmap( NULL, len, PROT_READ, MAP_SHARED, fd, 0 );
#else
            /*
             * FIXME: Can g_alloca() be used here? It's very fast, but is it safe?
             * Actually, we can allocate a block of memory with the size of mime_cache_max_extent,
             * then we don't need to  do dynamic allocation/free every time, but multi-threading
             * will be a nightmare, so...
             */
            /* try to lock the common buffer */
            if( G_LIKELY( G_TRYLOCK( mime_magic_buf ) ) )
                data = mime_magic_buf;
            else /* the buffer is in use, allocate new one */
                data = g_malloc( len );

            len = read( fd, data, len );

            if( G_UNLIKELY( len == -1 ) )
            {
                if( G_LIKELY( data == mime_magic_buf ) )
                    G_UNLOCK( mime_magic_buf );
                else
                    g_free( data );
                data = (void*)-1;
            }
#endif
            if( data != (void*)-1 )
            {
                int i;
                for( i = 0; ! type && i < n_caches; ++i )
                    type = mime_cache_lookup_magic( caches[i], data, len );

                /* Check for executable file */
                if( ! type && g_file_test( filepath, G_FILE_TEST_IS_EXECUTABLE ) )
                    type = XDG_MIME_TYPE_EXECUTABLE;

                /* fallback: check for plain text */
                if( ! type )
                {
                    if( mime_type_is_data_plain_text( data, len > TEXT_MAX_EXTENT ? TEXT_MAX_EXTENT : len ) )
                        type = XDG_MIME_TYPE_PLAIN_TEXT;
                }

#ifdef HAVE_MMAP
                munmap ( (char*)data, len );
#else
                if( G_LIKELY( data == mime_magic_buf ) )
                    G_UNLOCK( mime_magic_buf );  /* unlock the common buffer */
                else /* we use our own buffer */
                    g_free( data );
#endif
            }
            close( fd );
        }
    }
    else
    {
        /* empty file can be viewed as text file */
        type = XDG_MIME_TYPE_PLAIN_TEXT;
    }
    return type && *type ? type : XDG_MIME_TYPE_UNKNOWN;
}