VALUE renet_connection_initialize(VALUE self, VALUE host, VALUE port, VALUE channels, VALUE download, VALUE upload) { rb_funcall(mENet, rb_intern("initialize"), 0); Connection* connection; /* Now that we're releasing the GIL while waiting for enet_host_service we need a lock to prevent potential segfaults if another thread tries to do an operation on same connection */ VALUE lock = rb_mutex_new(); rb_iv_set(self, "@lock", lock); rb_mutex_lock(lock); Data_Get_Struct(self, Connection, connection); Check_Type(host, T_STRING); if (enet_address_set_host(connection->address, StringValuePtr(host)) != 0) { rb_raise(rb_eStandardError, "Cannot set address"); } connection->address->port = NUM2UINT(port); connection->channels = NUM2UINT(channels); connection->online = 0; connection->host = enet_host_create(NULL, 1, connection->channels, NUM2UINT(download), NUM2UINT(upload)); if (connection->host == NULL) { rb_raise(rb_eStandardError, "Cannot create host"); } rb_iv_set(self, "@total_sent_data", INT2FIX(0)); rb_iv_set(self, "@total_received_data", INT2FIX(0)); rb_iv_set(self, "@total_sent_packets", INT2FIX(0)); rb_iv_set(self, "@total_received_packets", INT2FIX(0)); rb_mutex_unlock(lock); return self; }
/* The core API functions for a connection: renet_connection_connect renet_connection_disconnect renet_connection_send_packet renet_connection_send_queued_packets renet_connection_update renet_connection_use_compression renet_connection_online */ VALUE renet_connection_connect(VALUE self, VALUE timeout) { Connection* connection; Data_Get_Struct(self, Connection, connection); VALUE lock = rb_iv_get(self, "@lock"); rb_mutex_lock(lock); VALUE rv = Qfalse; if (connection->online == 0) { connection->peer = enet_host_connect(connection->host, connection->address, connection->channels, 0); if (connection->peer == NULL) { rb_raise(rb_eStandardError, "Cannot connect to remote host"); } if (service(self, connection, NUM2UINT(timeout)) > 0 && connection->event->type == ENET_EVENT_TYPE_CONNECT) { connection->online = 1; renet_connection_execute_on_connection(self); rv = Qtrue; } else { enet_peer_reset(connection->peer); } } rb_mutex_unlock(lock); return rv; }
VALUE renet_server_initialize(VALUE self, VALUE port, VALUE n_peers, VALUE channels, VALUE download, VALUE upload) { rb_funcall(mENet, rb_intern("initialize"), 0); Server* server; Data_Get_Struct(self, Server, server); VALUE lock = rb_mutex_new(); rb_iv_set(self, "@lock", lock); rb_mutex_lock(lock); server->address->host = ENET_HOST_ANY; server->address->port = NUM2UINT(port); server->channels = NUM2UINT(channels); server->host = enet_host_create(server->address, NUM2UINT(n_peers), server->channels, NUM2UINT(download), NUM2UINT(upload)); if (server->host == NULL) { rb_raise(rb_eStandardError, "Cannot create server"); } rb_iv_set(self, "@total_sent_data", INT2FIX(0)); rb_iv_set(self, "@total_received_data", INT2FIX(0)); rb_iv_set(self, "@total_sent_packets", INT2FIX(0)); rb_iv_set(self, "@total_received_packets", INT2FIX(0)); rb_mutex_unlock(lock); return self; }
VALUE renet_connection_send_packet(VALUE self, VALUE data, VALUE flag, VALUE channel) { Connection* connection; Data_Get_Struct(self, Connection, connection); VALUE lock = rb_iv_get(self, "@lock"); rb_mutex_lock(lock); Check_Type(data, T_STRING); char* cdata = StringValuePtr(data); ENetPacket* packet; if (connection->online != 0) { if (flag == Qtrue) { packet = enet_packet_create(cdata, RSTRING_LEN(data) + 1, ENET_PACKET_FLAG_RELIABLE); } else { packet = enet_packet_create(cdata, RSTRING_LEN(data) + 1, 0); } enet_peer_send(connection->peer, NUM2UINT(channel), packet); } rb_mutex_unlock(lock); return Qnil; }
VALUE renet_server_send_queued_packets(VALUE self) { Server* server; Data_Get_Struct(self, Server, server); VALUE lock = rb_iv_get(self, "@lock"); rb_mutex_lock(lock); enet_host_flush(server->host); rb_mutex_unlock(lock); return Qnil; }
void renet_connection_execute_on_disconnection(VALUE self) { VALUE method = rb_iv_get(self, "@on_disconnection"); if (method != Qnil) { VALUE lock = rb_iv_get(self, "@lock"); rb_mutex_unlock(lock); rb_funcall(method, rb_intern("call"), 0); rb_mutex_lock(lock); } }
VALUE renet_server_disconnect_client(VALUE self, VALUE peer_id) { Server* server; Data_Get_Struct(self, Server, server); VALUE lock = rb_iv_get(self, "@lock"); rb_mutex_lock(lock); enet_peer_disconnect_now(&(server->host->peers[NUM2UINT(peer_id)]), 0); renet_server_execute_on_disconnection(self, peer_id); rb_mutex_unlock(lock); return Qtrue; }
void renet_server_execute_on_connection(VALUE self, VALUE peer_id, VALUE ip) { VALUE method = rb_iv_get(self, "@on_connection"); if (method != Qnil) { VALUE lock = rb_iv_get(self, "@lock"); rb_mutex_unlock(lock); rb_funcall(method, rb_intern("call"), 2, peer_id, ip); rb_mutex_lock(lock); } }
VALUE rb_xthread_monitor_enter(VALUE self) { xthread_monitor_t *mon; VALUE th = rb_thread_current(); GetXThreadMonitorPtr(self, mon); if (mon->owner != th) { rb_mutex_lock(mon->mutex); mon->owner = th; } mon->count += 1; }
static void grpc_ruby_init_threads() { // Avoid calling into ruby library (when creating threads here) // in gpr_once_init. In general, it appears to be unsafe to call // into the ruby library while holding a non-ruby mutex, because a gil yield // could end up trying to lock onto that same mutex and deadlocking. rb_mutex_lock(bg_thread_init_rb_mu); if (!bg_thread_init_done) { grpc_rb_event_queue_thread_start(); grpc_rb_channel_polling_thread_start(); bg_thread_init_done = 1; } rb_mutex_unlock(bg_thread_init_rb_mu); }
VALUE renet_connection_send_queued_packets(VALUE self) { Connection* connection; Data_Get_Struct(self, Connection, connection); VALUE lock = rb_iv_get(self, "@lock"); rb_mutex_lock(lock); if (connection->online != 0) { enet_host_flush(connection->host); } rb_mutex_unlock(lock); return Qnil; }
VALUE renet_server_use_compression(VALUE self, VALUE flag) { Server* server; Data_Get_Struct(self, Server, server); VALUE lock = rb_iv_get(self, "@lock"); rb_mutex_lock(lock); if (flag == Qtrue) { enet_host_compress_with_range_coder(server->host); } else { enet_host_compress(server->host, NULL); } rb_mutex_unlock(lock); return Qnil; }
void renet_connection_execute_on_packet_receive(VALUE self, ENetPacket * const packet, enet_uint8 channelID) { VALUE method = rb_iv_get(self, "@on_packet_receive"); VALUE data = rb_str_new((char const *)packet->data, packet->dataLength); /* marshal data and then destroy packet if we don't do this now the packet might become invalid before we get back and we'd get a segfault when we attempt to destroy */ enet_packet_destroy(packet); if (method != Qnil) { VALUE lock = rb_iv_get(self, "@lock"); rb_mutex_unlock(lock); rb_funcall(method, rb_intern("call"), 2, data, UINT2NUM(channelID)); rb_mutex_lock(lock); } }
VALUE renet_connection_disconnect(VALUE self, VALUE timeout) { Connection* connection; Data_Get_Struct(self, Connection, connection); VALUE lock = rb_iv_get(self, "@lock"); rb_mutex_lock(lock); VALUE rv = Qfalse; if (connection->online == 0) { rv = Qtrue; } else { connection->online = 0; enet_peer_disconnect(connection->peer, 0); while (service(self, connection, NUM2UINT(timeout)) > 0) { switch (connection->event->type) { case ENET_EVENT_TYPE_NONE: break; case ENET_EVENT_TYPE_CONNECT: break; case ENET_EVENT_TYPE_RECEIVE: enet_packet_destroy (connection->event->packet); break; case ENET_EVENT_TYPE_DISCONNECT: rv = Qtrue; break; } if (rv == Qtrue) { break; } } if (rv != Qtrue) { enet_peer_disconnect_now(connection->peer, 0); } } rb_mutex_unlock(lock); return rv; }
VALUE renet_connection_use_compression(VALUE self, VALUE flag) { Connection* connection; Data_Get_Struct(self, Connection, connection); VALUE lock = rb_iv_get(self, "@lock"); rb_mutex_lock(lock); if (flag == Qtrue) { enet_host_compress_with_range_coder(connection->host); } else { enet_host_compress(connection->host, NULL); } rb_mutex_unlock(lock); return Qnil; }
VALUE renet_server_broadcast_packet(VALUE self, VALUE data, VALUE flag, VALUE channel) { Server* server; Data_Get_Struct(self, Server, server); VALUE lock = rb_iv_get(self, "@lock"); rb_mutex_lock(lock); Check_Type(data, T_STRING); char* cdata = StringValuePtr(data); ENetPacket* packet; if (flag == Qtrue) { packet = enet_packet_create(cdata, RSTRING_LEN(data), ENET_PACKET_FLAG_RELIABLE); } else { packet = enet_packet_create(cdata, RSTRING_LEN(data), 0); } enet_host_broadcast(server->host, NUM2UINT(channel), packet); rb_mutex_unlock(lock); return Qnil; }
static VALUE mutex_synchronize(VALUE self, SEL sel) { rb_mutex_lock(self, 0); return rb_ensure(sync_body, Qundef, sync_ensure, self); }
VALUE rb_mutex_synchronize(VALUE mutex, VALUE (*func)(VALUE arg), VALUE arg) { rb_mutex_lock(mutex); return rb_ensure(func, arg, rb_mutex_unlock, mutex); }
VALUE renet_server_update(VALUE self, VALUE timeout) { Server* server; Data_Get_Struct(self, Server, server); VALUE lock = rb_iv_get(self, "@lock"); rb_mutex_lock(lock); int peer_id; /* wait up to timeout milliseconds for a packet */ if (service(self, server, NUM2UINT(timeout)) > 0) { do { switch (server->event->type) { case ENET_EVENT_TYPE_NONE: break; case ENET_EVENT_TYPE_CONNECT: server->n_clients += 1; enet_address_get_host_ip(&(server->event->peer->address), server->conn_ip, 20); peer_id = (int)(server->event->peer - server->host->peers); renet_server_execute_on_connection(self, INT2NUM(peer_id), rb_str_new2(server->conn_ip)); break; case ENET_EVENT_TYPE_RECEIVE: peer_id = (int)(server->event->peer - server->host->peers); renet_server_execute_on_packet_receive(self, INT2NUM(peer_id), server->event->packet, server->event->channelID); break; case ENET_EVENT_TYPE_DISCONNECT: server->n_clients -= 1; peer_id = (int)(server->event->peer - server->host->peers); server->event->peer->data = NULL; renet_server_execute_on_disconnection(self, INT2NUM(peer_id)); break; } } while (service(self, server, 0) > 0); } /* we are unlocking now because it's important to unlock before going back into ruby land (which rb_funcall will do). If we don't then an exception can leave the locks in an inconsistent state */ rb_mutex_unlock(lock); { VALUE total = rb_iv_get(self, "@total_sent_data"); VALUE result = rb_funcall( total , rb_intern("+") , 1 , UINT2NUM(server->host->totalSentData)); rb_iv_set(self, "@total_sent_data", result); server->host->totalSentData = 0; } { VALUE total = rb_iv_get(self, "@total_received_data"); VALUE result = rb_funcall( total , rb_intern("+") , 1 , UINT2NUM(server->host->totalReceivedData)); rb_iv_set(self, "@total_received_data", result); server->host->totalReceivedData = 0; } { VALUE total = rb_iv_get(self, "@total_sent_packets"); VALUE result = rb_funcall( total , rb_intern("+") , 1 , UINT2NUM(server->host->totalSentPackets)); rb_iv_set(self, "@total_sent_packets", result); server->host->totalSentPackets = 0; } { VALUE total = rb_iv_get(self, "@total_received_packets"); VALUE result = rb_funcall( total , rb_intern("+") , 1 , UINT2NUM(server->host->totalReceivedPackets)); rb_iv_set(self, "@total_received_packets", result); server->host->totalReceivedPackets = 0; } return Qtrue; }
static VALUE mutex_lock(VALUE self) { return rb_mutex_lock(self, 0); }
VALUE renet_connection_update(VALUE self, VALUE timeout) { Connection* connection; Data_Get_Struct(self, Connection, connection); VALUE lock = rb_iv_get(self, "@lock"); rb_mutex_lock(lock); VALUE rv = Qfalse; if (connection->online != 0) { /* wait up to timeout milliseconds for a packet */ if (service(self, connection, NUM2UINT(timeout)) > 0) { do { switch (connection->event->type) { case ENET_EVENT_TYPE_NONE: break; case ENET_EVENT_TYPE_CONNECT: break; case ENET_EVENT_TYPE_RECEIVE: renet_connection_execute_on_packet_receive(self, connection->event->packet, connection->event->channelID); break; case ENET_EVENT_TYPE_DISCONNECT: connection->online = 0; renet_connection_execute_on_disconnection(self); break; } } /* Do not use a timeout for subsequent services or we could get stuck here forever */ while ((connection->online != 0) && (service(self, connection, 0) > 0)); } rv = Qtrue; } /* we are unlocking now because it's important to unlock before going back into ruby land (which rb_funcall will do). If we don't then an exception can leave the locks in an inconsistent state */ rb_mutex_unlock(lock); if (rv == Qtrue) { { VALUE total = rb_iv_get(self, "@total_sent_data"); VALUE result = rb_funcall( total , rb_intern("+") , 1 , UINT2NUM(connection->host->totalSentData)); rb_iv_set(self, "@total_sent_data", result); connection->host->totalSentData = 0; } { VALUE total = rb_iv_get(self, "@total_received_data"); VALUE result = rb_funcall( total , rb_intern("+") , 1 , UINT2NUM(connection->host->totalReceivedData)); rb_iv_set(self, "@total_received_data", result); connection->host->totalReceivedData = 0; } { VALUE total = rb_iv_get(self, "@total_sent_packets"); VALUE result = rb_funcall( total , rb_intern("+") , 1 , UINT2NUM(connection->host->totalSentPackets)); rb_iv_set(self, "@total_sent_packets", result); connection->host->totalSentPackets = 0; } { VALUE total = rb_iv_get(self, "@total_received_packets"); VALUE result = rb_funcall( total , rb_intern("+") , 1 , UINT2NUM(connection->host->totalReceivedPackets)); rb_iv_set(self, "@total_received_packets", result); connection->host->totalReceivedPackets = 0; } } return rv; }
void rho_ruby_lock_mutex(VALUE val) { rb_mutex_lock(val); }
static VALUE rb_mutex_synchronize(VALUE self) { rb_mutex_lock(self); return rb_ensure(rb_yield, Qundef, rb_mutex_unlock, self); }