gssize g_tls_connection_base_write (GTlsConnectionBase *tls, const void *buffer, gsize count, gboolean blocking, GCancellable *cancellable, GError **error) { GTlsConnectionBaseStatus status; gssize nwrote; do { if (!claim_op (tls, G_TLS_CONNECTION_BASE_OP_WRITE, blocking, cancellable, error)) return -1; status = G_TLS_CONNECTION_BASE_GET_CLASS (tls)-> write_fn (tls, buffer, count, blocking, &nwrote, cancellable, error); yield_op (tls, G_TLS_CONNECTION_BASE_OP_WRITE, status); } while (status == G_TLS_CONNECTION_BASE_REHANDSHAKE); if (status == G_TLS_CONNECTION_BASE_OK) return nwrote; else return -1; }
static void implicit_handshake_completed (GObject *object, GAsyncResult *result, gpointer user_data) { GTlsConnectionBase *tls = G_TLS_CONNECTION_BASE (object); g_mutex_lock (&tls->op_mutex); tls->need_finish_handshake = TRUE; g_mutex_unlock (&tls->op_mutex); yield_op (tls, G_TLS_CONNECTION_BASE_OP_HANDSHAKE, G_TLS_CONNECTION_BASE_OK); }
static gboolean do_implicit_handshake (GTlsConnectionBase *tls, gboolean blocking, GCancellable *cancellable, GError **error) { /* We have op_mutex */ tls->implicit_handshake = g_task_new (tls, cancellable, implicit_handshake_completed, NULL); g_task_set_source_tag (tls->implicit_handshake, do_implicit_handshake); if (blocking) { GError *my_error = NULL; gboolean success; g_mutex_unlock (&tls->op_mutex); g_task_run_in_thread_sync (tls->implicit_handshake, handshake_thread); success = finish_handshake (tls, tls->implicit_handshake, &my_error); g_clear_object (&tls->implicit_handshake); yield_op (tls, G_TLS_CONNECTION_BASE_OP_HANDSHAKE, G_TLS_CONNECTION_BASE_OK); g_mutex_lock (&tls->op_mutex); if (my_error) g_propagate_error (error, my_error); return success; } else { g_task_run_in_thread (tls->implicit_handshake, handshake_thread); g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK, _("Operation would block")); return FALSE; } }
gssize g_tls_connection_base_read (GTlsConnectionBase *tls, void *buffer, gsize count, gboolean blocking, GCancellable *cancellable, GError **error) { GTlsConnectionBaseStatus status; gssize nread; do { if (!claim_op (tls, G_TLS_CONNECTION_BASE_OP_READ, blocking, cancellable, error)) return -1; if (tls->app_data_buf && !tls->handshaking) { nread = MIN (count, tls->app_data_buf->len); memcpy (buffer, tls->app_data_buf->data, nread); if (nread == tls->app_data_buf->len) g_clear_pointer (&tls->app_data_buf, g_byte_array_unref); else g_byte_array_remove_range (tls->app_data_buf, 0, nread); status = G_TLS_CONNECTION_BASE_OK; } else { status = G_TLS_CONNECTION_BASE_GET_CLASS (tls)-> read_fn (tls, buffer, count, blocking, &nread, cancellable, error); } yield_op (tls, G_TLS_CONNECTION_BASE_OP_READ, status); } while (status == G_TLS_CONNECTION_BASE_REHANDSHAKE); if (status == G_TLS_CONNECTION_BASE_OK) return nread; else return -1; }
static void async_handshake_thread (GTask *task, gpointer object, gpointer task_data, GCancellable *cancellable) { GTlsConnectionBase *tls = object; handshake_thread (task, object, task_data, cancellable); g_mutex_lock (&tls->op_mutex); tls->need_finish_handshake = TRUE; /* yield_op will clear handshaking too, but we don't want the * connection to be briefly "handshaking && need_finish_handshake" * after we unlock the mutex. */ tls->handshaking = FALSE; g_mutex_unlock (&tls->op_mutex); yield_op (tls, G_TLS_CONNECTION_BASE_OP_HANDSHAKE, G_TLS_CONNECTION_BASE_OK); }
static gboolean g_tls_connection_base_handshake (GTlsConnection *conn, GCancellable *cancellable, GError **error) { GTlsConnectionBase *tls = G_TLS_CONNECTION_BASE (conn); GTask *task; gboolean success; GError *my_error = NULL; task = g_task_new (conn, cancellable, NULL, NULL); g_task_set_source_tag (task, g_tls_connection_base_handshake); g_task_run_in_thread_sync (task, handshake_thread); success = finish_handshake (tls, task, &my_error); g_object_unref (task); yield_op (tls, G_TLS_CONNECTION_BASE_OP_HANDSHAKE, G_TLS_CONNECTION_BASE_OK); if (my_error) g_propagate_error (error, my_error); return success; }
static void test_case_yield_op( Thread_Control *executing, Scheduler_SMP_Node *executing_node, Thread_Control *other, Scheduler_SMP_Node_state start_state, Scheduler_SMP_Node_state new_state ) { Thread_Control *needs_help; _Thread_Change_priority(executing, 4, false); _Thread_Change_priority(other, 4, false); switch (start_state) { case SCHEDULER_SMP_NODE_SCHEDULED: switch (new_state) { case SCHEDULER_SMP_NODE_SCHEDULED: _Thread_Change_priority(executing, 2, false); _Thread_Change_priority(other, 3, false); break; case SCHEDULER_SMP_NODE_READY: _Thread_Change_priority(executing, 2, false); _Thread_Change_priority(other, 2, false); break; default: rtems_test_assert(0); break; } break; case SCHEDULER_SMP_NODE_READY: switch (new_state) { case SCHEDULER_SMP_NODE_SCHEDULED: rtems_test_assert(0); break; case SCHEDULER_SMP_NODE_READY: _Thread_Change_priority(executing, 3, false); _Thread_Change_priority(other, 2, false); break; default: rtems_test_assert(0); break; } break; default: rtems_test_assert(0); break; } rtems_test_assert(executing_node->state == start_state); needs_help = yield_op(executing); rtems_test_assert(executing_node->state == new_state); if (start_state != new_state) { switch (start_state) { case SCHEDULER_SMP_NODE_SCHEDULED: rtems_test_assert(needs_help == executing); break; case SCHEDULER_SMP_NODE_READY: rtems_test_assert(needs_help == other); break; default: rtems_test_assert(0); break; } } else { rtems_test_assert(needs_help == NULL); } }
gboolean g_tls_connection_base_close_internal (GIOStream *stream, GTlsDirection direction, GCancellable *cancellable, GError **error) { GTlsConnectionBase *tls = G_TLS_CONNECTION_BASE (stream); GTlsConnectionBaseOp op; GTlsConnectionBaseStatus status; gboolean success = TRUE; GError *close_error = NULL, *stream_error = NULL; /* This can be called from g_io_stream_close(), g_input_stream_close() or * g_output_stream_close(). In all cases, we only do the close_fn() for * writing. The difference is how we set the flags on this class and how * the underlying stream is closed. */ g_return_val_if_fail (direction != G_TLS_DIRECTION_NONE, FALSE); if (direction == G_TLS_DIRECTION_BOTH) op = G_TLS_CONNECTION_BASE_OP_CLOSE_BOTH; else if (direction == G_TLS_DIRECTION_READ) op = G_TLS_CONNECTION_BASE_OP_CLOSE_READ; else op = G_TLS_CONNECTION_BASE_OP_CLOSE_WRITE; if (!claim_op (tls, op, TRUE, cancellable, error)) return FALSE; if (tls->ever_handshaked && !tls->write_closed && direction & G_TLS_DIRECTION_WRITE) { status = G_TLS_CONNECTION_BASE_GET_CLASS (tls)-> close_fn (tls, cancellable, &close_error); tls->write_closed = TRUE; } else status = G_TLS_CONNECTION_BASE_OK; if (!tls->read_closed && direction & G_TLS_DIRECTION_READ) tls->read_closed = TRUE; /* Close the underlying streams. Do this even if the close_fn() call failed, * as the parent GIOStream will have set its internal closed flag and hence * this implementation will never be called again. */ if (direction == G_TLS_DIRECTION_BOTH) success = g_io_stream_close (tls->base_io_stream, cancellable, &stream_error); else if (direction & G_TLS_DIRECTION_READ) success = g_input_stream_close (g_io_stream_get_input_stream (tls->base_io_stream), cancellable, &stream_error); else if (direction & G_TLS_DIRECTION_WRITE) success = g_output_stream_close (g_io_stream_get_output_stream (tls->base_io_stream), cancellable, &stream_error); yield_op (tls, op, status); /* Propagate errors. */ if (status != G_TLS_CONNECTION_BASE_OK) { g_propagate_error (error, close_error); g_clear_error (&stream_error); } else if (!success) { g_propagate_error (error, stream_error); g_clear_error (&close_error); } return success && status == G_TLS_CONNECTION_BASE_OK; }