Commit 3dbfdf90 authored by lahiker42's avatar lahiker42

rpc works!


git-svn-id: https://protobuf-c.googlecode.com/svn/trunk@126 00440858-1255-0410-a3e6-75ea37f81c3a
parent d2995318
/* NOTE: this may not work very well on windows, where i'm
not sure that "SOCKETs" are allocated nicely like
file-descriptors are */
#include <assert.h> #include <assert.h>
#include <alloca.h> #include <alloca.h>
#include <sys/time.h> #include <sys/time.h>
...@@ -7,10 +10,14 @@ ...@@ -7,10 +10,14 @@
#include <sys/poll.h> #include <sys/poll.h>
#include <limits.h> #include <limits.h>
#include <errno.h> #include <errno.h>
#include <signal.h>
#include "protobuf-c-dispatch.h" #include "protobuf-c-dispatch.h"
#include "gskrbtreemacros.h" #include "gskrbtreemacros.h"
#include "gsklistmacros.h" #include "gsklistmacros.h"
#define DEBUG_DISPATCH_INTERNALS 0
#define DEBUG_DISPATCH 0
#define protobuf_c_assert(condition) assert(condition) #define protobuf_c_assert(condition) assert(condition)
#define ALLOC_WITH_ALLOCATOR(allocator, size) ((allocator)->alloc ((allocator)->allocator_data, (size))) #define ALLOC_WITH_ALLOCATOR(allocator, size) ((allocator)->alloc ((allocator)->allocator_data, (size)))
...@@ -106,16 +113,30 @@ struct _ProtobufCDispatchIdle ...@@ -106,16 +113,30 @@ struct _ProtobufCDispatchIdle
ProtobufCDispatch *protobuf_c_dispatch_new (ProtobufCAllocator *allocator) ProtobufCDispatch *protobuf_c_dispatch_new (ProtobufCAllocator *allocator)
{ {
RealDispatch *rv = ALLOC (sizeof (RealDispatch)); RealDispatch *rv = ALLOC (sizeof (RealDispatch));
struct timeval tv;
rv->base.n_changes = 0; rv->base.n_changes = 0;
rv->notifies_desired_alloced = 8; rv->notifies_desired_alloced = 8;
rv->base.notifies_desired = ALLOC (sizeof (ProtobufC_FDNotify) * rv->notifies_desired_alloced); rv->base.notifies_desired = ALLOC (sizeof (ProtobufC_FDNotify) * rv->notifies_desired_alloced);
rv->base.n_notifies_desired = 0;
rv->callbacks = ALLOC (sizeof (Callback) * rv->notifies_desired_alloced); rv->callbacks = ALLOC (sizeof (Callback) * rv->notifies_desired_alloced);
rv->changes_alloced = 8; rv->changes_alloced = 8;
rv->base.changes = ALLOC (sizeof (ProtobufC_FDNotify) * rv->changes_alloced); rv->base.changes = ALLOC (sizeof (ProtobufC_FDNotify) * rv->changes_alloced);
rv->fd_map_size = 16; rv->fd_map_size = 16;
rv->fd_map = ALLOC (sizeof (FDMap) * rv->fd_map_size); rv->fd_map = ALLOC (sizeof (FDMap) * rv->fd_map_size);
rv->allocator = allocator; rv->allocator = allocator;
rv->timer_tree = NULL;
rv->first_idle = rv->last_idle = NULL;
memset (rv->fd_map, 255, sizeof (FDMap) * rv->fd_map_size); memset (rv->fd_map, 255, sizeof (FDMap) * rv->fd_map_size);
rv->recycled_idles = NULL;
rv->recycled_timeouts = NULL;
/* need to handle SIGPIPE more gracefully than default */
signal (SIGPIPE, SIG_IGN);
gettimeofday (&tv, NULL);
rv->base.last_dispatch_secs = tv.tv_sec;
rv->base.last_dispatch_usecs = tv.tv_usec;
return &rv->base; return &rv->base;
} }
...@@ -124,7 +145,20 @@ protobuf_c_dispatch_free(ProtobufCDispatch *dispatch) ...@@ -124,7 +145,20 @@ protobuf_c_dispatch_free(ProtobufCDispatch *dispatch)
{ {
RealDispatch *d = (RealDispatch *) dispatch; RealDispatch *d = (RealDispatch *) dispatch;
ProtobufCAllocator *allocator = d->allocator; ProtobufCAllocator *allocator = d->allocator;
while (d->recycled_timeouts != NULL)
{
ProtobufCDispatchTimer *t = d->recycled_timeouts;
d->recycled_timeouts = t->right;
FREE (t);
}
while (d->recycled_idles != NULL)
{
ProtobufCDispatchIdle *i = d->recycled_idles;
d->recycled_idles = i->next;
FREE (i);
}
FREE (d->base.notifies_desired); FREE (d->base.notifies_desired);
FREE (d->base.changes);
FREE (d->callbacks); FREE (d->callbacks);
FREE (d->fd_map); FREE (d->fd_map);
FREE (d); FREE (d);
...@@ -138,9 +172,9 @@ protobuf_c_dispatch_peek_allocator (ProtobufCDispatch *dispatch) ...@@ -138,9 +172,9 @@ protobuf_c_dispatch_peek_allocator (ProtobufCDispatch *dispatch)
} }
/* TODO: perhaps thread-private dispatches make more sense? */ /* TODO: perhaps thread-private dispatches make more sense? */
static ProtobufCDispatch *def = NULL;
ProtobufCDispatch *protobuf_c_dispatch_default (void) ProtobufCDispatch *protobuf_c_dispatch_default (void)
{ {
static ProtobufCDispatch *def = NULL;
if (def == NULL) if (def == NULL)
def = protobuf_c_dispatch_new (&protobuf_c_default_allocator); def = protobuf_c_dispatch_new (&protobuf_c_default_allocator);
return def; return def;
...@@ -187,6 +221,9 @@ allocate_notifies_desired_index (RealDispatch *d) ...@@ -187,6 +221,9 @@ allocate_notifies_desired_index (RealDispatch *d)
d->base.notifies_desired = n; d->base.notifies_desired = n;
d->notifies_desired_alloced = new_size; d->notifies_desired_alloced = new_size;
} }
#if DEBUG_DISPATCH_INTERNALS
fprintf (stderr, "allocate_notifies_desired_index: returning %u\n", rv);
#endif
return rv; return rv;
} }
static unsigned static unsigned
...@@ -230,12 +267,16 @@ deallocate_notify_desired_index (RealDispatch *d, ...@@ -230,12 +267,16 @@ deallocate_notify_desired_index (RealDispatch *d,
unsigned nd_ind = d->fd_map[fd].notify_desired_index; unsigned nd_ind = d->fd_map[fd].notify_desired_index;
unsigned from = d->base.n_notifies_desired - 1; unsigned from = d->base.n_notifies_desired - 1;
unsigned from_fd; unsigned from_fd;
#if DEBUG_DISPATCH_INTERNALS
fprintf (stderr, "deallocate_notify_desired_index: fd=%d, nd_ind=%u\n",fd,nd_ind);
#endif
d->fd_map[fd].notify_desired_index = -1;
if (nd_ind == from) if (nd_ind == from)
{ {
d->base.n_notifies_desired--; d->base.n_notifies_desired--;
return; return;
} }
from_fd = d->base.notifies_desired[nd_ind].fd; from_fd = d->base.notifies_desired[from].fd;
d->fd_map[from_fd].notify_desired_index = nd_ind; d->fd_map[from_fd].notify_desired_index = nd_ind;
d->base.notifies_desired[nd_ind] = d->base.notifies_desired[from]; d->base.notifies_desired[nd_ind] = d->base.notifies_desired[from];
d->base.n_notifies_desired--; d->base.n_notifies_desired--;
...@@ -253,6 +294,12 @@ protobuf_c_dispatch_watch_fd (ProtobufCDispatch *dispatch, ...@@ -253,6 +294,12 @@ protobuf_c_dispatch_watch_fd (ProtobufCDispatch *dispatch,
RealDispatch *d = (RealDispatch *) dispatch; RealDispatch *d = (RealDispatch *) dispatch;
unsigned f = fd; /* avoid tiring compiler warnings: "comparison of signed versus unsigned" */ unsigned f = fd; /* avoid tiring compiler warnings: "comparison of signed versus unsigned" */
unsigned nd_ind, change_ind; unsigned nd_ind, change_ind;
#if DEBUG_DISPATCH
fprintf (stderr, "dispatch: watch_fd: %d, %s%s\n",
fd,
(events&PROTOBUF_C_EVENT_READABLE)?"r":"",
(events&PROTOBUF_C_EVENT_WRITABLE)?"w":"");
#endif
if (callback == NULL) if (callback == NULL)
assert (events == 0); assert (events == 0);
else else
...@@ -260,12 +307,14 @@ protobuf_c_dispatch_watch_fd (ProtobufCDispatch *dispatch, ...@@ -260,12 +307,14 @@ protobuf_c_dispatch_watch_fd (ProtobufCDispatch *dispatch,
ensure_fd_map_big_enough (d, f); ensure_fd_map_big_enough (d, f);
if (d->fd_map[f].notify_desired_index == -1) if (d->fd_map[f].notify_desired_index == -1)
{ {
d->fd_map[f].notify_desired_index = allocate_notifies_desired_index (d); if (callback != NULL)
nd_ind = d->fd_map[f].notify_desired_index = allocate_notifies_desired_index (d);
} }
else else
{ {
if (callback == NULL) if (callback == NULL)
deallocate_notify_desired_index (d, f); deallocate_notify_desired_index (d, f);
else
nd_ind = d->fd_map[f].notify_desired_index; nd_ind = d->fd_map[f].notify_desired_index;
} }
if (callback == NULL) if (callback == NULL)
...@@ -304,6 +353,9 @@ protobuf_c_dispatch_fd_closed(ProtobufCDispatch *dispatch, ...@@ -304,6 +353,9 @@ protobuf_c_dispatch_fd_closed(ProtobufCDispatch *dispatch,
{ {
unsigned f = fd; unsigned f = fd;
RealDispatch *d = (RealDispatch *) dispatch; RealDispatch *d = (RealDispatch *) dispatch;
#if DEBUG_DISPATCH
fprintf (stderr, "dispatch: fd %d closed\n", fd);
#endif
ensure_fd_map_big_enough (d, f); ensure_fd_map_big_enough (d, f);
d->fd_map[fd].closed_since_notify_started = 1; d->fd_map[fd].closed_since_notify_started = 1;
if (d->fd_map[f].change_index != -1) if (d->fd_map[f].change_index != -1)
...@@ -330,8 +382,6 @@ protobuf_c_dispatch_dispatch (ProtobufCDispatch *dispatch, ...@@ -330,8 +382,6 @@ protobuf_c_dispatch_dispatch (ProtobufCDispatch *dispatch,
unsigned i; unsigned i;
FDMap *fd_map = d->fd_map; FDMap *fd_map = d->fd_map;
struct timeval tv; struct timeval tv;
if (n_notifies == 0)
return;
fd_max = 0; fd_max = 0;
for (i = 0; i < n_notifies; i++) for (i = 0; i < n_notifies; i++)
if (fd_max < (unsigned) notifies[i].fd) if (fd_max < (unsigned) notifies[i].fd)
...@@ -352,6 +402,20 @@ protobuf_c_dispatch_dispatch (ProtobufCDispatch *dispatch, ...@@ -352,6 +402,20 @@ protobuf_c_dispatch_dispatch (ProtobufCDispatch *dispatch,
} }
} }
/* handle idle functions */
while (d->first_idle != NULL)
{
ProtobufCDispatchIdle *idle = d->first_idle;
ProtobufCDispatchIdleFunc func = idle->func;
void *data = idle->func_data;
GSK_LIST_REMOVE_FIRST (GET_IDLE_LIST (d));
idle->func = NULL; /* set to NULL to render remove_idle a no-op */
func (dispatch, data);
idle->next = d->recycled_idles;
d->recycled_idles = idle;
}
/* handle timers */ /* handle timers */
gettimeofday (&tv, NULL); gettimeofday (&tv, NULL);
...@@ -439,7 +503,9 @@ protobuf_c_dispatch_run (ProtobufCDispatch *dispatch) ...@@ -439,7 +503,9 @@ protobuf_c_dispatch_run (ProtobufCDispatch *dispatch)
/* compute timeout */ /* compute timeout */
if (d->first_idle != NULL) if (d->first_idle != NULL)
{
timeout = 0; timeout = 0;
}
else if (d->timer_tree == NULL) else if (d->timer_tree == NULL)
timeout = -1; timeout = -1;
else else
...@@ -516,6 +582,7 @@ protobuf_c_dispatch_add_timer(ProtobufCDispatch *dispatch, ...@@ -516,6 +582,7 @@ protobuf_c_dispatch_add_timer(ProtobufCDispatch *dispatch,
{ {
RealDispatch *d = (RealDispatch *) dispatch; RealDispatch *d = (RealDispatch *) dispatch;
ProtobufCDispatchTimer *rv; ProtobufCDispatchTimer *rv;
ProtobufCDispatchTimer *at;
ProtobufCDispatchTimer *conflict; ProtobufCDispatchTimer *conflict;
protobuf_c_assert (func != NULL); protobuf_c_assert (func != NULL);
if (d->recycled_timeouts != NULL) if (d->recycled_timeouts != NULL)
...@@ -533,6 +600,17 @@ protobuf_c_dispatch_add_timer(ProtobufCDispatch *dispatch, ...@@ -533,6 +600,17 @@ protobuf_c_dispatch_add_timer(ProtobufCDispatch *dispatch,
rv->func_data = func_data; rv->func_data = func_data;
rv->dispatch = d; rv->dispatch = d;
GSK_RBTREE_INSERT (GET_TIMER_TREE (d), rv, conflict); GSK_RBTREE_INSERT (GET_TIMER_TREE (d), rv, conflict);
/* is this the first element in the tree */
for (at = rv; at != NULL; at = at->parent)
if (at->parent && at->parent->right == at)
break;
if (at == NULL) /* yes, so set the public members */
{
dispatch->has_timeout = 1;
dispatch->timeout_secs = rv->timeout_secs;
dispatch->timeout_usecs = rv->timeout_usecs;
}
return rv; return rv;
} }
...@@ -609,8 +687,20 @@ protobuf_c_dispatch_add_idle (ProtobufCDispatch *dispatch, ...@@ -609,8 +687,20 @@ protobuf_c_dispatch_add_idle (ProtobufCDispatch *dispatch,
void void
protobuf_c_dispatch_remove_idle (ProtobufCDispatchIdle *idle) protobuf_c_dispatch_remove_idle (ProtobufCDispatchIdle *idle)
{ {
if (idle->func != NULL)
{
RealDispatch *d = idle->dispatch; RealDispatch *d = idle->dispatch;
GSK_LIST_REMOVE (GET_IDLE_LIST (d), idle); GSK_LIST_REMOVE (GET_IDLE_LIST (d), idle);
idle->next = d->recycled_idles; idle->next = d->recycled_idles;
d->recycled_idles = idle; d->recycled_idles = idle;
}
}
void protobuf_c_dispatch_destroy_default (void)
{
if (def)
{
ProtobufCDispatch *kill = def;
def = NULL;
protobuf_c_dispatch_free (kill);
}
} }
...@@ -115,5 +115,6 @@ struct _ProtobufCDispatch ...@@ -115,5 +115,6 @@ struct _ProtobufCDispatch
/* private data follows */ /* private data follows */
}; };
void protobuf_c_dispatch_destroy_default (void);
#endif #endif
This diff is collapsed.
...@@ -37,5 +37,5 @@ BUILT_SOURCES = generated-code/test.pb-c.c generated-code/test.pb-c.h \ ...@@ -37,5 +37,5 @@ BUILT_SOURCES = generated-code/test.pb-c.c generated-code/test.pb-c.h \
generated-code/test-full.pb.cc generated-code/test-full.pb.h \ generated-code/test-full.pb.cc generated-code/test-full.pb.h \
generated-code/test-full-cxx-output.inc generated-code/test-full-cxx-output.inc
DISTCLEANFILES = $(BUILT_SOURCES) DISTCLEANFILES = $(BUILT_SOURCES)
TESTS = test-generated-code test-generated-code2 TESTS = test-generated-code test-generated-code2 test-rpc
EXTRA_DIST = test.proto test-full.proto common-test-arrays.h EXTRA_DIST = test.proto test-full.proto common-test-arrays.h
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include "generated-code/test.pb-c.h" #include "generated-code/test.pb-c.h"
#include <google/protobuf-c/protobuf-c-rpc.h> #include <google/protobuf-c/protobuf-c-rpc.h>
static void
message (const char *format, ...)
{
va_list args;
va_start (args, format);
vfprintf (stderr, format, args);
va_end (args);
fputc ('\n', stderr);
}
/* --- A local service --- */ /* --- A local service --- */
static void static void
test__by_name (Foo__DirLookup_Service *service, test__by_name (Foo__DirLookup_Service *service,
...@@ -35,6 +47,7 @@ test__by_name (Foo__DirLookup_Service *service, ...@@ -35,6 +47,7 @@ test__by_name (Foo__DirLookup_Service *service,
if (number != NULL) if (number != NULL)
{ {
pn.number = number; pn.number = number;
pn.has_type = 1;
pn.type = type; pn.type = type;
person.n_phone = 1; person.n_phone = 1;
person.phone = pns; person.phone = pns;
...@@ -158,8 +171,10 @@ int main() ...@@ -158,8 +171,10 @@ int main()
ProtobufC_RPC_Client *client; ProtobufC_RPC_Client *client;
ProtobufC_RPC_Server *server; ProtobufC_RPC_Server *server;
message ("testing local service");
test_service (local_service); test_service (local_service);
message ("creating client");
/* Create a client with no server. Verify that /* Create a client with no server. Verify that
the client returns a failure immediately */ the client returns a failure immediately */
remote_service = protobuf_c_rpc_client_new (PROTOBUF_C_RPC_ADDRESS_LOCAL, remote_service = protobuf_c_rpc_client_new (PROTOBUF_C_RPC_ADDRESS_LOCAL,
...@@ -172,18 +187,23 @@ int main() ...@@ -172,18 +187,23 @@ int main()
is_done = 0; is_done = 0;
protobuf_c_dispatch_add_timer_millis (protobuf_c_dispatch_default (), protobuf_c_dispatch_add_timer_millis (protobuf_c_dispatch_default (),
250, set_boolean_true, &is_done); 250, set_boolean_true, &is_done);
message ("verify client cannot connect");
while (!is_done) while (!is_done)
{ {
protobuf_c_dispatch_run (protobuf_c_dispatch_default ()); protobuf_c_dispatch_run (protobuf_c_dispatch_default ());
assert (!protobuf_c_rpc_client_is_connected (client)); assert (!protobuf_c_rpc_client_is_connected (client));
} }
message ("testing unconnected client");
test_defunct_client (remote_service);
message ("creating server");
/* Create a server and wait for the client to connect. */ /* Create a server and wait for the client to connect. */
server = protobuf_c_rpc_server_new (PROTOBUF_C_RPC_ADDRESS_LOCAL, server = protobuf_c_rpc_server_new (PROTOBUF_C_RPC_ADDRESS_LOCAL,
"test.socket", "test.socket",
local_service, local_service,
NULL); NULL);
assert (server != NULL); assert (server != NULL);
message ("waiting to connect");
is_done = 0; is_done = 0;
protobuf_c_dispatch_add_timer_millis (protobuf_c_dispatch_default (), protobuf_c_dispatch_add_timer_millis (protobuf_c_dispatch_default (),
250, set_boolean_true, &is_done); 250, set_boolean_true, &is_done);
...@@ -201,23 +221,25 @@ int main() ...@@ -201,23 +221,25 @@ int main()
protobuf_c_dispatch_run (protobuf_c_dispatch_default ()); protobuf_c_dispatch_run (protobuf_c_dispatch_default ());
/* Test the client */ /* Test the client */
message ("testing client");
test_service (remote_service); test_service (remote_service);
/* Destroy the server and ensure that a request is failed in /* Destroy the server and ensure that a request is failed in
a timely fashion. */ a timely fashion. */
message ("destroying server");
protobuf_c_rpc_server_destroy (server, 0); protobuf_c_rpc_server_destroy (server, 0);
server = NULL; server = NULL;
message ("test client has no data");
test_defunct_client (remote_service); test_defunct_client (remote_service);
/* Create a server again and wait for the client to reconnect. */ /* Create a server again and wait for the client to reconnect. */
message ("creating server again");
server = protobuf_c_rpc_server_new (PROTOBUF_C_RPC_ADDRESS_LOCAL, server = protobuf_c_rpc_server_new (PROTOBUF_C_RPC_ADDRESS_LOCAL,
"test.socket", "test.socket",
local_service, local_service,
NULL); NULL);
assert (server != NULL); assert (server != NULL);
is_done = 0; is_done = 0;
while (!is_done)
protobuf_c_dispatch_run (protobuf_c_dispatch_default ());
protobuf_c_dispatch_add_timer_millis (protobuf_c_dispatch_default (), protobuf_c_dispatch_add_timer_millis (protobuf_c_dispatch_default (),
250, set_boolean_true, &is_done); 250, set_boolean_true, &is_done);
while (!is_done) while (!is_done)
...@@ -225,14 +247,21 @@ int main() ...@@ -225,14 +247,21 @@ int main()
assert (protobuf_c_rpc_client_is_connected (client)); assert (protobuf_c_rpc_client_is_connected (client));
/* Test the client again, for kicks. */ /* Test the client again, for kicks. */
message ("testing client again");
test_service (remote_service); test_service (remote_service);
/* Destroy the client */ /* Destroy the client */
message ("destroying client");
protobuf_c_service_destroy (remote_service); protobuf_c_service_destroy (remote_service);
/* Destroy the server */ /* Destroy the server */
message ("destroying server");
protobuf_c_rpc_server_destroy (server, 0); protobuf_c_rpc_server_destroy (server, 0);
protobuf_c_dispatch_destroy_default ();
unlink ("test.socket");
return 0; return 0;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment