mirror of
https://github.com/neovim/neovim.git
synced 2025-09-13 14:58:18 +00:00
msgpack_rpc/server.c: Use a garray over a kmap.
Testing of server_start() and server_stop() found that after adding a server at address addr, pmap_has(addr) would always return true, but pmap_get(addr) would always return NULL. Since a client is only expected to have a small number of servers, an array may be more efficient than a hash map, anyway. Discussion: https://github.com/neovim/neovim/pull/1302#issuecomment-88487148
This commit is contained in:
@@ -9,11 +9,11 @@
|
|||||||
#include "nvim/msgpack_rpc/server.h"
|
#include "nvim/msgpack_rpc/server.h"
|
||||||
#include "nvim/os/os.h"
|
#include "nvim/os/os.h"
|
||||||
#include "nvim/ascii.h"
|
#include "nvim/ascii.h"
|
||||||
|
#include "nvim/garray.h"
|
||||||
#include "nvim/vim.h"
|
#include "nvim/vim.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
#include "nvim/log.h"
|
#include "nvim/log.h"
|
||||||
#include "nvim/tempfile.h"
|
#include "nvim/tempfile.h"
|
||||||
#include "nvim/map.h"
|
|
||||||
#include "nvim/path.h"
|
#include "nvim/path.h"
|
||||||
|
|
||||||
#define MAX_CONNECTIONS 32
|
#define MAX_CONNECTIONS 32
|
||||||
@@ -27,6 +27,9 @@ typedef enum {
|
|||||||
} ServerType;
|
} ServerType;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
// The address of a pipe, or string value of a tcp address.
|
||||||
|
char addr[ADDRESS_MAX_SIZE];
|
||||||
|
|
||||||
// Type of the union below
|
// Type of the union below
|
||||||
ServerType type;
|
ServerType type;
|
||||||
|
|
||||||
@@ -38,12 +41,11 @@ typedef struct {
|
|||||||
} tcp;
|
} tcp;
|
||||||
struct {
|
struct {
|
||||||
uv_pipe_t handle;
|
uv_pipe_t handle;
|
||||||
char addr[ADDRESS_MAX_SIZE];
|
|
||||||
} pipe;
|
} pipe;
|
||||||
} socket;
|
} socket;
|
||||||
} Server;
|
} Server;
|
||||||
|
|
||||||
static PMap(cstr_t) *servers = NULL;
|
static garray_T servers = GA_EMPTY_INIT_VALUE;
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "msgpack_rpc/server.c.generated.h"
|
# include "msgpack_rpc/server.c.generated.h"
|
||||||
@@ -52,7 +54,7 @@ static PMap(cstr_t) *servers = NULL;
|
|||||||
/// Initializes the module
|
/// Initializes the module
|
||||||
bool server_init(void)
|
bool server_init(void)
|
||||||
{
|
{
|
||||||
servers = pmap_new(cstr_t)();
|
ga_init(&servers, sizeof(Server *), 1);
|
||||||
|
|
||||||
if (!os_getenv(LISTEN_ADDRESS_ENV_VAR)) {
|
if (!os_getenv(LISTEN_ADDRESS_ENV_VAR)) {
|
||||||
char *listen_address = (char *)vim_tempname();
|
char *listen_address = (char *)vim_tempname();
|
||||||
@@ -63,22 +65,24 @@ bool server_init(void)
|
|||||||
return server_start((char *)os_getenv(LISTEN_ADDRESS_ENV_VAR)) == 0;
|
return server_start((char *)os_getenv(LISTEN_ADDRESS_ENV_VAR)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve the file handle from a server.
|
||||||
|
static uv_handle_t *server_handle(Server *server)
|
||||||
|
{
|
||||||
|
return server->type == kServerTypeTcp
|
||||||
|
? (uv_handle_t *)&server->socket.tcp.handle
|
||||||
|
: (uv_handle_t *) &server->socket.pipe.handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Teardown a single server
|
||||||
|
static void server_close_cb(Server **server)
|
||||||
|
{
|
||||||
|
uv_close(server_handle(*server), free_server);
|
||||||
|
}
|
||||||
|
|
||||||
/// Teardown the server module
|
/// Teardown the server module
|
||||||
void server_teardown(void)
|
void server_teardown(void)
|
||||||
{
|
{
|
||||||
if (!servers) {
|
GA_DEEP_CLEAR(&servers, Server *, server_close_cb);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Server *server;
|
|
||||||
|
|
||||||
map_foreach_value(servers, server, {
|
|
||||||
if (server->type == kServerTypeTcp) {
|
|
||||||
uv_close((uv_handle_t *)&server->socket.tcp.handle, free_server);
|
|
||||||
} else {
|
|
||||||
uv_close((uv_handle_t *)&server->socket.pipe.handle, free_server);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Starts listening on arbitrary tcp/unix addresses specified by
|
/// Starts listening on arbitrary tcp/unix addresses specified by
|
||||||
@@ -106,9 +110,11 @@ int server_start(const char *endpoint)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if the server already exists
|
// Check if the server already exists
|
||||||
if (pmap_has(cstr_t)(servers, addr)) {
|
for (int i = 0; i < servers.ga_len; i++) {
|
||||||
ELOG("Already listening on %s", addr);
|
if (strcmp(addr, ((Server **)servers.ga_data)[i]->addr) == 0) {
|
||||||
return 1;
|
ELOG("Already listening on %s", addr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerType server_type = kServerTypeTcp;
|
ServerType server_type = kServerTypeTcp;
|
||||||
@@ -154,6 +160,8 @@ int server_start(const char *endpoint)
|
|||||||
int result;
|
int result;
|
||||||
uv_stream_t *stream = NULL;
|
uv_stream_t *stream = NULL;
|
||||||
|
|
||||||
|
xstrlcpy(server->addr, addr, sizeof(server->addr));
|
||||||
|
|
||||||
if (server_type == kServerTypeTcp) {
|
if (server_type == kServerTypeTcp) {
|
||||||
// Listen on tcp address/port
|
// Listen on tcp address/port
|
||||||
uv_tcp_init(uv_default_loop(), &server->socket.tcp.handle);
|
uv_tcp_init(uv_default_loop(), &server->socket.tcp.handle);
|
||||||
@@ -163,10 +171,8 @@ int server_start(const char *endpoint)
|
|||||||
stream = (uv_stream_t *)&server->socket.tcp.handle;
|
stream = (uv_stream_t *)&server->socket.tcp.handle;
|
||||||
} else {
|
} else {
|
||||||
// Listen on named pipe or unix socket
|
// Listen on named pipe or unix socket
|
||||||
xstrlcpy(server->socket.pipe.addr, addr, sizeof(server->socket.pipe.addr));
|
|
||||||
uv_pipe_init(uv_default_loop(), &server->socket.pipe.handle, 0);
|
uv_pipe_init(uv_default_loop(), &server->socket.pipe.handle, 0);
|
||||||
result = uv_pipe_bind(&server->socket.pipe.handle,
|
result = uv_pipe_bind(&server->socket.pipe.handle, server->addr);
|
||||||
server->socket.pipe.addr);
|
|
||||||
stream = (uv_stream_t *)&server->socket.pipe.handle;
|
stream = (uv_stream_t *)&server->socket.pipe.handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,8 +200,10 @@ int server_start(const char *endpoint)
|
|||||||
}
|
}
|
||||||
|
|
||||||
server->type = server_type;
|
server->type = server_type;
|
||||||
// Add the server to the hash table
|
|
||||||
pmap_put(cstr_t)(servers, addr, server);
|
// Add the server to the list.
|
||||||
|
ga_grow(&servers, 1);
|
||||||
|
((Server **)servers.ga_data)[servers.ga_len++] = server;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -211,18 +219,27 @@ void server_stop(char *endpoint)
|
|||||||
// Trim to `ADDRESS_MAX_SIZE`
|
// Trim to `ADDRESS_MAX_SIZE`
|
||||||
xstrlcpy(addr, endpoint, sizeof(addr));
|
xstrlcpy(addr, endpoint, sizeof(addr));
|
||||||
|
|
||||||
if ((server = pmap_get(cstr_t)(servers, addr)) == NULL) {
|
int i = 0; // The index of the server whose address equals addr.
|
||||||
|
for (; i < servers.ga_len; i++) {
|
||||||
|
server = ((Server **)servers.ga_data)[i];
|
||||||
|
if (strcmp(addr, server->addr) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == servers.ga_len) {
|
||||||
ELOG("Not listening on %s", addr);
|
ELOG("Not listening on %s", addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server->type == kServerTypeTcp) {
|
uv_close(server_handle(server), free_server);
|
||||||
uv_close((uv_handle_t *)&server->socket.tcp.handle, free_server);
|
|
||||||
} else {
|
|
||||||
uv_close((uv_handle_t *)&server->socket.pipe.handle, free_server);
|
|
||||||
}
|
|
||||||
|
|
||||||
pmap_del(cstr_t)(servers, addr);
|
// Remove this server from the list by swapping it with the last item.
|
||||||
|
if (i != servers.ga_len - 1) {
|
||||||
|
((Server **)servers.ga_data)[i] =
|
||||||
|
((Server **)servers.ga_data)[servers.ga_len - 1];
|
||||||
|
}
|
||||||
|
servers.ga_len--;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void connection_cb(uv_stream_t *server, int status)
|
static void connection_cb(uv_stream_t *server, int status)
|
||||||
|
Reference in New Issue
Block a user