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); }
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); }
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; }
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; }
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; }
/* * 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; }