mirror of
https://github.com/protobuf-c/protobuf-c.git
synced 2024-12-29 23:42:12 +08:00
...
git-svn-id: https://protobuf-c.googlecode.com/svn/trunk@118 00440858-1255-0410-a3e6-75ea37f81c3a
This commit is contained in:
parent
e135ebd217
commit
f4e009d4bf
388
src/google/protobuf-c/gsklistmacros.h
Normal file
388
src/google/protobuf-c/gsklistmacros.h
Normal file
@ -0,0 +1,388 @@
|
|||||||
|
|
||||||
|
/* We define three data structures:
|
||||||
|
* 1. a Stack. a singly-ended, singly-linked list.
|
||||||
|
* 2. a Queue. a doubly-ended, singly-linked list.
|
||||||
|
* 3. a List. a doubly-ended, doubly-linked list.
|
||||||
|
*
|
||||||
|
* Stack operations:
|
||||||
|
* PUSH(stack, node) [O(1)]
|
||||||
|
* POP(stack, rv_node) [O(1)]
|
||||||
|
* INSERT_AFTER(stack, above_node, new_node) [O(1)]
|
||||||
|
* IS_EMPTY(stack) [O(1)]
|
||||||
|
* REVERSE(stack) [O(N)]
|
||||||
|
* SORT(stack, comparator) [O(NlogN)]
|
||||||
|
* GET_BOTTOM(stack, rv_node) [O(N)]
|
||||||
|
* Queue operations:
|
||||||
|
* ENQUEUE(queue, node) [O(1)]
|
||||||
|
* DEQUEUE(queue, rv_node) [O(1)]
|
||||||
|
* PREPEND(queue, node) [O(1)]
|
||||||
|
* IS_EMPTY(queue) [O(1)]
|
||||||
|
* REVERSE(queue) [O(N)]
|
||||||
|
* SORT(queue, comparator) [O(NlogN)]
|
||||||
|
* List operations:
|
||||||
|
* PREPEND(list, node) [O(1)]
|
||||||
|
* APPEND(list, node) [O(1)]
|
||||||
|
* REMOVE_FIRST(list) [O(1)]
|
||||||
|
* REMOVE_LAST(list) [O(1)]
|
||||||
|
* REMOVE(list, node) [O(1)]
|
||||||
|
* INSERT_AFTER(list, position_node, new_node) [O(1)]
|
||||||
|
* INSERT_BEFORE(list, position_node, new_node) [O(1)]
|
||||||
|
* IS_EMPTY(list) [O(1)]
|
||||||
|
* REVERSE(list) [O(N)]
|
||||||
|
* SORT(list) [O(NlogN)]
|
||||||
|
*
|
||||||
|
* note: the SORT operation is stable, i.e. if two
|
||||||
|
* elements are equal according to the comparator,
|
||||||
|
* then their relative order in the list
|
||||||
|
* will be preserved.
|
||||||
|
*
|
||||||
|
* In the above, 'stack', 'queue', and 'list' are
|
||||||
|
* a comma-separated list of arguments, actually.
|
||||||
|
* In particular:
|
||||||
|
* stack => NodeType*, top, next_member_name
|
||||||
|
* queue => NodeType*, head, tail, next_member_name
|
||||||
|
* list => NodeType*, first, last, prev_member_name, next_member_name
|
||||||
|
* We recommend making macros that end in GET_STACK_ARGS, GET_QUEUE_ARGS,
|
||||||
|
* and GET_LIST_ARGS that return the relevant N-tuples.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define GSK_LOG2_MAX_LIST_SIZE (GLIB_SIZEOF_SIZE_T*8)
|
||||||
|
|
||||||
|
/* --- Stacks --- */
|
||||||
|
#define GSK_STACK_PUSH(stack, node) GSK_STACK_PUSH_(stack, node)
|
||||||
|
#define GSK_STACK_POP(stack, rv_node) GSK_STACK_POP_(stack, rv_node)
|
||||||
|
#define GSK_STACK_INSERT_AFTER(stack, above_node, new_node) \
|
||||||
|
GSK_STACK_INSERT_AFTER_(stack, above_node, new_node)
|
||||||
|
#define GSK_STACK_IS_EMPTY(stack) GSK_STACK_IS_EMPTY_(stack)
|
||||||
|
#define GSK_STACK_REVERSE(stack) GSK_STACK_REVERSE_(stack)
|
||||||
|
#define GSK_STACK_FOREACH(stack, iter_var, code) GSK_STACK_FOREACH_(stack, iter_var, code)
|
||||||
|
#define GSK_STACK_SORT(stack, comparator) GSK_STACK_SORT_(stack, comparator)
|
||||||
|
#define GSK_STACK_GET_BOTTOM(stack, rv_node) GSK_STACK_GET_BOTTOM_(stack, rv_node)
|
||||||
|
|
||||||
|
#define GSK_STACK_PUSH_(type, top, next, node) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
type _gsk_tmp = (node); \
|
||||||
|
_gsk_tmp->next = (top); \
|
||||||
|
(top) = _gsk_tmp; \
|
||||||
|
}G_STMT_END
|
||||||
|
#define GSK_STACK_POP_(type, top, next, rv_node) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
rv_node = (top); \
|
||||||
|
(top) = (top)->next; \
|
||||||
|
}G_STMT_END
|
||||||
|
#define GSK_STACK_INSERT_AFTER_(type, top, next, above_node, new_node) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
type _gsk_tmp = (new_node); \
|
||||||
|
type _gsk_above = (above_node); \
|
||||||
|
_gsk_tmp->next = _gsk_above->next; \
|
||||||
|
_gsk_above->next = _gsk_tmp; \
|
||||||
|
}G_STMT_END
|
||||||
|
#define GSK_STACK_IS_EMPTY_(type, top, next) \
|
||||||
|
((top) == NULL)
|
||||||
|
#define GSK_STACK_REVERSE_(type, top, next) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
type _gsk___prev = NULL; \
|
||||||
|
type _gsk___at = (top); \
|
||||||
|
while (_gsk___at != NULL) \
|
||||||
|
{ \
|
||||||
|
type _gsk__next = _gsk___at->next; \
|
||||||
|
_gsk___at->next = _gsk___prev; \
|
||||||
|
_gsk___prev = _gsk___at; \
|
||||||
|
_gsk___at = _gsk__next; \
|
||||||
|
} \
|
||||||
|
(top) = _gsk___prev; \
|
||||||
|
}G_STMT_END
|
||||||
|
#define GSK_STACK_FOREACH_(type, top, next, iter_var, code) \
|
||||||
|
for (iter_var = top; iter_var != NULL; ) \
|
||||||
|
{ \
|
||||||
|
type _gsk__next = iter_var->next; \
|
||||||
|
code; \
|
||||||
|
iter_var = _gsk__next; \
|
||||||
|
}
|
||||||
|
/* sort algorithm:
|
||||||
|
* in order to implement SORT in a macro, it cannot use recursion.
|
||||||
|
* but that's ok because you can just manually implement a stack,
|
||||||
|
* which is probably faster anyways.
|
||||||
|
*/
|
||||||
|
#define GSK_STACK_SORT_(type, top, next, comparator) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
type _gsk_stack[GSK_LOG2_MAX_LIST_SIZE]; \
|
||||||
|
guint _gsk_stack_size = 0; \
|
||||||
|
guint _gsk_i; \
|
||||||
|
type _gsk_at; \
|
||||||
|
for (_gsk_at = top; _gsk_at != NULL; ) \
|
||||||
|
{ \
|
||||||
|
type _gsk_a = _gsk_at; \
|
||||||
|
type _gsk_b; \
|
||||||
|
type _gsk_cur_list; \
|
||||||
|
int _gsk_comparator_rv; \
|
||||||
|
_gsk_at = _gsk_at->next; \
|
||||||
|
if (_gsk_at) \
|
||||||
|
{ \
|
||||||
|
_gsk_b = _gsk_at; \
|
||||||
|
_gsk_at = _gsk_at->next; \
|
||||||
|
comparator (_gsk_a, _gsk_b, _gsk_comparator_rv); \
|
||||||
|
if (_gsk_comparator_rv > 0) \
|
||||||
|
{ \
|
||||||
|
/* sort first two elements */ \
|
||||||
|
type _gsk_swap = _gsk_b; \
|
||||||
|
_gsk_b = _gsk_a; \
|
||||||
|
_gsk_a = _gsk_swap; \
|
||||||
|
_gsk_a->next = _gsk_b; \
|
||||||
|
_gsk_b->next = NULL; \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
/* first two elements already sorted */ \
|
||||||
|
_gsk_b->next = NULL; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
/* only one element remains */ \
|
||||||
|
_gsk_a->next = NULL; \
|
||||||
|
_gsk_at = NULL; \
|
||||||
|
} \
|
||||||
|
_gsk_cur_list = _gsk_a; \
|
||||||
|
\
|
||||||
|
/* merge _gsk_cur_list up the stack */ \
|
||||||
|
for (_gsk_i = 0; TRUE; _gsk_i++) \
|
||||||
|
{ \
|
||||||
|
/* expanding the stack is marked unlikely, */ \
|
||||||
|
/* since in the case it matters (where the number */ \
|
||||||
|
/* of elements is big), the stack rarely grows. */ \
|
||||||
|
if (G_UNLIKELY (_gsk_i == _gsk_stack_size)) \
|
||||||
|
{ \
|
||||||
|
_gsk_stack[_gsk_stack_size++] = _gsk_cur_list; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
else if (_gsk_stack[_gsk_i] == NULL) \
|
||||||
|
{ \
|
||||||
|
_gsk_stack[_gsk_i] = _gsk_cur_list; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
/* Merge _gsk_stack[_gsk_i] and _gsk_cur_list. */ \
|
||||||
|
type _gsk_merge_list = _gsk_stack[_gsk_i]; \
|
||||||
|
type _gsk_new_cur_list; \
|
||||||
|
_gsk_stack[_gsk_i] = NULL; \
|
||||||
|
\
|
||||||
|
_GSK_MERGE_NONEMPTY_LISTS (_gsk_merge_list, \
|
||||||
|
_gsk_cur_list, \
|
||||||
|
_gsk_new_cur_list, \
|
||||||
|
type, next, comparator); \
|
||||||
|
_gsk_cur_list = _gsk_new_cur_list; \
|
||||||
|
_gsk_stack[_gsk_i] = NULL; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* combine all the elements on the stack into a final output */ \
|
||||||
|
top = NULL; \
|
||||||
|
for (_gsk_i = 0; _gsk_i < _gsk_stack_size; _gsk_i++) \
|
||||||
|
if (_gsk_stack[_gsk_i] != NULL) \
|
||||||
|
{ \
|
||||||
|
if (top == NULL) \
|
||||||
|
top = _gsk_stack[_gsk_i]; \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
type _gsk_new_top; \
|
||||||
|
_GSK_MERGE_NONEMPTY_LISTS (_gsk_stack[_gsk_i], \
|
||||||
|
top, \
|
||||||
|
_gsk_new_top, \
|
||||||
|
type, next, comparator); \
|
||||||
|
top = _gsk_new_top; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}G_STMT_END
|
||||||
|
|
||||||
|
#define GSK_STACK_GET_BOTTOM_(type, top, next, rv_node) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
rv_node = top; \
|
||||||
|
if (rv_node != NULL) \
|
||||||
|
while (rv_node->next) \
|
||||||
|
rv_node = rv_node->next; \
|
||||||
|
}G_STMT_END
|
||||||
|
|
||||||
|
/* --- Queues --- */
|
||||||
|
#define GSK_QUEUE_ENQUEUE(queue, node) GSK_QUEUE_ENQUEUE_(queue, node)
|
||||||
|
#define GSK_QUEUE_DEQUEUE(queue, rv_node) GSK_QUEUE_DEQUEUE_(queue, rv_node)
|
||||||
|
#define GSK_QUEUE_PREPEND(queue, node) GSK_QUEUE_PREPEND_(queue, node)
|
||||||
|
#define GSK_QUEUE_IS_EMPTY(queue) GSK_QUEUE_IS_EMPTY_(queue)
|
||||||
|
#define GSK_QUEUE_REVERSE(queue) GSK_QUEUE_REVERSE_(queue)
|
||||||
|
#define GSK_QUEUE_SORT(queue, comparator) GSK_QUEUE_SORT_(queue, comparator)
|
||||||
|
|
||||||
|
#define GSK_QUEUE_ENQUEUE_(type, head, tail, next, node) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
type _gsk_tmp = (node); \
|
||||||
|
if (tail) \
|
||||||
|
tail->next = _gsk_tmp; \
|
||||||
|
else \
|
||||||
|
head = _gsk_tmp; \
|
||||||
|
tail = _gsk_tmp; \
|
||||||
|
node->next = NULL; \
|
||||||
|
}G_STMT_END
|
||||||
|
#define GSK_QUEUE_DEQUEUE_(type, head, tail, next, rv_node) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
rv_node = head; \
|
||||||
|
if (head) \
|
||||||
|
{ \
|
||||||
|
head = head->next; \
|
||||||
|
if (head == NULL) \
|
||||||
|
tail = NULL; \
|
||||||
|
} \
|
||||||
|
}G_STMT_END
|
||||||
|
#define GSK_QUEUE_PREPEND_(type, head, tail, next, node) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
type _gsk_tmp = (node); \
|
||||||
|
_gsk_tmp->next = head; \
|
||||||
|
head = _gsk_tmp; \
|
||||||
|
if (tail == NULL) \
|
||||||
|
tail = head; \
|
||||||
|
}G_STMT_END
|
||||||
|
|
||||||
|
#define GSK_QUEUE_IS_EMPTY_(type, head, tail, next) \
|
||||||
|
((head) == NULL)
|
||||||
|
|
||||||
|
#define GSK_QUEUE_REVERSE_(type, head, tail, next) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
type _gsk_queue_new_tail = head; \
|
||||||
|
GSK_STACK_REVERSE_(type, head, next); \
|
||||||
|
tail = _gsk_queue_new_tail; \
|
||||||
|
}G_STMT_END
|
||||||
|
|
||||||
|
#define GSK_QUEUE_SORT_(type, head, tail, next, comparator) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
GSK_STACK_SORT_(type, head, next, comparator); \
|
||||||
|
GSK_STACK_GET_BOTTOM_(type, head, next, tail); \
|
||||||
|
}G_STMT_END
|
||||||
|
|
||||||
|
/* --- List --- */
|
||||||
|
#define GSK_LIST_PREPEND(list, node) GSK_LIST_PREPEND_(list, node)
|
||||||
|
#define GSK_LIST_APPEND(list, node) GSK_LIST_APPEND_(list, node)
|
||||||
|
#define GSK_LIST_REMOVE_FIRST(list) GSK_LIST_REMOVE_FIRST_(list)
|
||||||
|
#define GSK_LIST_REMOVE_LAST(list) GSK_LIST_REMOVE_LAST_(list)
|
||||||
|
#define GSK_LIST_REMOVE(list, node) GSK_LIST_REMOVE_(list, node)
|
||||||
|
#define GSK_LIST_INSERT_AFTER(list, at, node) GSK_LIST_INSERT_AFTER_(list, at, node)
|
||||||
|
#define GSK_LIST_INSERT_BEFORE(list, at, node) GSK_LIST_INSERT_BEFORE_(list, at, node)
|
||||||
|
#define GSK_LIST_IS_EMPTY(list) GSK_LIST_IS_EMPTY_(list)
|
||||||
|
#define GSK_LIST_REVERSE(list) GSK_LIST_REVERSE_(list)
|
||||||
|
#define GSK_LIST_SORT(list, comparator) GSK_LIST_SORT_(list, comparator)
|
||||||
|
|
||||||
|
#define GSK_LIST_PREPEND_(type, first, last, prev, next, node) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
type _gsk_tmp = (node); \
|
||||||
|
if (first) \
|
||||||
|
first->prev = (_gsk_tmp); \
|
||||||
|
else \
|
||||||
|
last = (_gsk_tmp); \
|
||||||
|
node->next = first; \
|
||||||
|
node->prev = NULL; \
|
||||||
|
first = node; \
|
||||||
|
}G_STMT_END
|
||||||
|
#define GSK_LIST_APPEND_(type, first, last, prev, next, node) \
|
||||||
|
GSK_LIST_PREPEND_(type, last, first, next, prev, node)
|
||||||
|
#define GSK_LIST_REMOVE_FIRST_(type, first, last, prev, next) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
first = first->next; \
|
||||||
|
if (first == NULL) \
|
||||||
|
last = NULL; \
|
||||||
|
else \
|
||||||
|
first->prev = NULL; \
|
||||||
|
}G_STMT_END
|
||||||
|
#define GSK_LIST_REMOVE_LAST_(type, first, last, prev, next) \
|
||||||
|
GSK_LIST_REMOVE_FIRST_(type, last, first, next, prev)
|
||||||
|
#define GSK_LIST_REMOVE_(type, first, last, prev, next, node) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
type _gsk_tmp = (node); \
|
||||||
|
if (_gsk_tmp->prev) \
|
||||||
|
_gsk_tmp->prev->next = _gsk_tmp->next; \
|
||||||
|
else \
|
||||||
|
first = _gsk_tmp->next; \
|
||||||
|
if (_gsk_tmp->next) \
|
||||||
|
_gsk_tmp->next->prev = _gsk_tmp->prev; \
|
||||||
|
else \
|
||||||
|
last = _gsk_tmp->prev; \
|
||||||
|
}G_STMT_END
|
||||||
|
|
||||||
|
#define GSK_LIST_INSERT_AFTER_(type, first, last, prev, next, at, node) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
type _gsk_at = (at); \
|
||||||
|
type _gsk_node = (node); \
|
||||||
|
_gsk_node->prev = _gsk_at; \
|
||||||
|
_gsk_node->next = _gsk_at->next; \
|
||||||
|
if (_gsk_node->next) \
|
||||||
|
_gsk_node->next->prev = _gsk_node; \
|
||||||
|
else \
|
||||||
|
last = _gsk_node; \
|
||||||
|
_gsk_at->next = _gsk_node; \
|
||||||
|
}G_STMT_END
|
||||||
|
#define GSK_LIST_INSERT_BEFORE_(type, first, last, prev, next, at, node)\
|
||||||
|
GSK_LIST_INSERT_AFTER_(type, last, first, next, prev, at, node)
|
||||||
|
#define GSK_LIST_IS_EMPTY_(type, first, last, prev, next) \
|
||||||
|
((first) == NULL)
|
||||||
|
#define GSK_LIST_REVERSE_(type, first, last, prev, next) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
type _gsk_at = first; \
|
||||||
|
first = last; \
|
||||||
|
last = _gsk_at; \
|
||||||
|
while (_gsk_at) \
|
||||||
|
{ \
|
||||||
|
type _gsk_old_next = _gsk_at->next; \
|
||||||
|
_gsk_at->next = _gsk_at->prev; \
|
||||||
|
_gsk_at->prev = _gsk_old_next; \
|
||||||
|
_gsk_at = _gsk_old_next; \
|
||||||
|
} \
|
||||||
|
}G_STMT_END
|
||||||
|
#define GSK_LIST_SORT_(type, first, last, prev, next, comparator) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
type _gsk_prev = NULL; \
|
||||||
|
type _gsk_at; \
|
||||||
|
GSK_STACK_SORT_(type, first, next, comparator); \
|
||||||
|
for (_gsk_at = first; _gsk_at; _gsk_at = _gsk_at->next) \
|
||||||
|
{ \
|
||||||
|
_gsk_at->prev = _gsk_prev; \
|
||||||
|
_gsk_prev = _gsk_at; \
|
||||||
|
} \
|
||||||
|
last = _gsk_prev; \
|
||||||
|
}G_STMT_END
|
||||||
|
|
||||||
|
/* --- Internals --- */
|
||||||
|
#define _GSK_MERGE_NONEMPTY_LISTS(a,b,out,type,next,comparator) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
type _gsk_out_at; \
|
||||||
|
int _gsk_comparator_rv; \
|
||||||
|
/* merge 'a' and 'b' into 'out' -- in order to make the sort stable,*/ \
|
||||||
|
/* always put elements if 'a' first in the event of a tie (i.e. */ \
|
||||||
|
/* when comparator_rv==0) */ \
|
||||||
|
comparator (a, b, _gsk_comparator_rv); \
|
||||||
|
if (_gsk_comparator_rv <= 0) \
|
||||||
|
{ \
|
||||||
|
out = a; \
|
||||||
|
a = a->next; \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
out = b; \
|
||||||
|
b = b->next; \
|
||||||
|
} \
|
||||||
|
_gsk_out_at = out; \
|
||||||
|
while (a && b) \
|
||||||
|
{ \
|
||||||
|
comparator (a, b, _gsk_comparator_rv); \
|
||||||
|
if (_gsk_comparator_rv <= 0) \
|
||||||
|
{ \
|
||||||
|
_gsk_out_at->next = a; \
|
||||||
|
_gsk_out_at = a; \
|
||||||
|
a = a->next; \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
_gsk_out_at->next = b; \
|
||||||
|
_gsk_out_at = b; \
|
||||||
|
b = b->next; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
_gsk_out_at->next = (a != NULL) ? a : b; \
|
||||||
|
}G_STMT_END
|
@ -119,17 +119,19 @@ protobuf_c_data_buffer_cleanup_recycling_bin ()
|
|||||||
|
|
||||||
/* --- Public methods --- */
|
/* --- Public methods --- */
|
||||||
/**
|
/**
|
||||||
* protobuf_c_data_buffer_construct:
|
* protobuf_c_data_buffer_init:
|
||||||
* @buffer: buffer to initialize (as empty).
|
* @buffer: buffer to initialize (as empty).
|
||||||
*
|
*
|
||||||
* Construct an empty buffer out of raw memory.
|
* Construct an empty buffer out of raw memory.
|
||||||
* (This is equivalent to filling the buffer with 0s)
|
* (This is equivalent to filling the buffer with 0s)
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
protobuf_c_data_buffer_construct(ProtobufCDataBuffer *buffer)
|
protobuf_c_data_buffer_init(ProtobufCDataBuffer *buffer,
|
||||||
|
ProtobufCAllocator *allocator)
|
||||||
{
|
{
|
||||||
buffer->first_frag = buffer->last_frag = NULL;
|
buffer->first_frag = buffer->last_frag = NULL;
|
||||||
buffer->size = 0;
|
buffer->size = 0;
|
||||||
|
buffer->allocator = allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(GSK_DEBUG) || GSK_DEBUG_BUFFER_ALLOCATIONS
|
#if defined(GSK_DEBUG) || GSK_DEBUG_BUFFER_ALLOCATIONS
|
||||||
@ -708,7 +710,7 @@ protobuf_c_data_buffer_clear(ProtobufCDataBuffer *to_destroy)
|
|||||||
* returns: its index in the buffer, or -1 if the character
|
* returns: its index in the buffer, or -1 if the character
|
||||||
* is not in the buffer.
|
* is not in the buffer.
|
||||||
*/
|
*/
|
||||||
ssize_t
|
int
|
||||||
protobuf_c_data_buffer_index_of(ProtobufCDataBuffer *buffer,
|
protobuf_c_data_buffer_index_of(ProtobufCDataBuffer *buffer,
|
||||||
char char_to_find)
|
char char_to_find)
|
||||||
{
|
{
|
||||||
@ -1103,242 +1105,3 @@ protobuf_c_data_buffer_polystr_index_of (ProtobufCDataBuffer *buffer,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* --- ProtobufCDataBufferIterator --- */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* protobuf_c_data_buffer_iterator_construct:
|
|
||||||
* @iterator: to initialize.
|
|
||||||
* @to_iterate: the buffer to walk through.
|
|
||||||
*
|
|
||||||
* Initialize a new #ProtobufCDataBufferIterator.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
protobuf_c_data_buffer_iterator_construct (ProtobufCDataBufferIterator *iterator,
|
|
||||||
ProtobufCDataBuffer *to_iterate)
|
|
||||||
{
|
|
||||||
iterator->fragment = to_iterate->first_frag;
|
|
||||||
if (iterator->fragment != NULL)
|
|
||||||
{
|
|
||||||
iterator->in_cur = 0;
|
|
||||||
iterator->cur_data = (uint8_t*)protobuf_c_data_buffer_fragment_start (iterator->fragment);
|
|
||||||
iterator->cur_length = iterator->fragment->buf_length;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
iterator->in_cur = 0;
|
|
||||||
iterator->cur_data = NULL;
|
|
||||||
iterator->cur_length = 0;
|
|
||||||
}
|
|
||||||
iterator->offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* protobuf_c_data_buffer_iterator_peek:
|
|
||||||
* @iterator: to peek data from.
|
|
||||||
* @out: to copy data into.
|
|
||||||
* @max_length: maximum number of bytes to write to @out.
|
|
||||||
*
|
|
||||||
* Peek data from the current position of an iterator.
|
|
||||||
* The iterator's position is not changed.
|
|
||||||
*
|
|
||||||
* returns: number of bytes peeked into @out.
|
|
||||||
*/
|
|
||||||
size_t
|
|
||||||
protobuf_c_data_buffer_iterator_peek (ProtobufCDataBufferIterator *iterator,
|
|
||||||
void *out,
|
|
||||||
size_t max_length)
|
|
||||||
{
|
|
||||||
ProtobufCDataBufferFragment *fragment = iterator->fragment;
|
|
||||||
|
|
||||||
size_t frag_length = iterator->cur_length;
|
|
||||||
const uint8_t *frag_data = iterator->cur_data;
|
|
||||||
size_t in_frag = iterator->in_cur;
|
|
||||||
|
|
||||||
size_t out_remaining = max_length;
|
|
||||||
uint8_t *out_at = out;
|
|
||||||
|
|
||||||
while (fragment != NULL)
|
|
||||||
{
|
|
||||||
size_t frag_remaining = frag_length - in_frag;
|
|
||||||
if (out_remaining <= frag_remaining)
|
|
||||||
{
|
|
||||||
memcpy (out_at, frag_data + in_frag, out_remaining);
|
|
||||||
out_remaining = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy (out_at, frag_data + in_frag, frag_remaining);
|
|
||||||
out_remaining -= frag_remaining;
|
|
||||||
out_at += frag_remaining;
|
|
||||||
|
|
||||||
fragment = fragment->next;
|
|
||||||
if (fragment != NULL)
|
|
||||||
{
|
|
||||||
frag_data = (uint8_t *) protobuf_c_data_buffer_fragment_start (fragment);
|
|
||||||
frag_length = fragment->buf_length;
|
|
||||||
}
|
|
||||||
in_frag = 0;
|
|
||||||
}
|
|
||||||
return max_length - out_remaining;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* protobuf_c_data_buffer_iterator_read:
|
|
||||||
* @iterator: to read data from.
|
|
||||||
* @out: to copy data into.
|
|
||||||
* @max_length: maximum number of bytes to write to @out.
|
|
||||||
*
|
|
||||||
* Peek data from the current position of an iterator.
|
|
||||||
* The iterator's position is updated to be at the end of
|
|
||||||
* the data read.
|
|
||||||
*
|
|
||||||
* returns: number of bytes read into @out.
|
|
||||||
*/
|
|
||||||
size_t
|
|
||||||
protobuf_c_data_buffer_iterator_read (ProtobufCDataBufferIterator *iterator,
|
|
||||||
void *out,
|
|
||||||
size_t max_length)
|
|
||||||
{
|
|
||||||
ProtobufCDataBufferFragment *fragment = iterator->fragment;
|
|
||||||
|
|
||||||
size_t frag_length = iterator->cur_length;
|
|
||||||
const uint8_t *frag_data = iterator->cur_data;
|
|
||||||
size_t in_frag = iterator->in_cur;
|
|
||||||
|
|
||||||
size_t out_remaining = max_length;
|
|
||||||
uint8_t *out_at = out;
|
|
||||||
|
|
||||||
while (fragment != NULL)
|
|
||||||
{
|
|
||||||
size_t frag_remaining = frag_length - in_frag;
|
|
||||||
if (out_remaining <= frag_remaining)
|
|
||||||
{
|
|
||||||
memcpy (out_at, frag_data + in_frag, out_remaining);
|
|
||||||
in_frag += out_remaining;
|
|
||||||
out_remaining = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy (out_at, frag_data + in_frag, frag_remaining);
|
|
||||||
out_remaining -= frag_remaining;
|
|
||||||
out_at += frag_remaining;
|
|
||||||
|
|
||||||
fragment = fragment->next;
|
|
||||||
if (fragment != NULL)
|
|
||||||
{
|
|
||||||
frag_data = (uint8_t *) protobuf_c_data_buffer_fragment_start (fragment);
|
|
||||||
frag_length = fragment->buf_length;
|
|
||||||
}
|
|
||||||
in_frag = 0;
|
|
||||||
}
|
|
||||||
iterator->in_cur = in_frag;
|
|
||||||
iterator->fragment = fragment;
|
|
||||||
iterator->cur_length = frag_length;
|
|
||||||
iterator->cur_data = frag_data;
|
|
||||||
iterator->offset += max_length - out_remaining;
|
|
||||||
return max_length - out_remaining;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* protobuf_c_data_buffer_iterator_find_char:
|
|
||||||
* @iterator: to advance.
|
|
||||||
* @c: the character to look for.
|
|
||||||
*
|
|
||||||
* If it exists,
|
|
||||||
* skip forward to the next instance of @c and return TRUE.
|
|
||||||
* Otherwise, do nothing and return FALSE.
|
|
||||||
*
|
|
||||||
* returns: whether the character was found.
|
|
||||||
*/
|
|
||||||
|
|
||||||
protobuf_c_boolean
|
|
||||||
protobuf_c_data_buffer_iterator_find_char (ProtobufCDataBufferIterator *iterator,
|
|
||||||
char c)
|
|
||||||
{
|
|
||||||
ProtobufCDataBufferFragment *fragment = iterator->fragment;
|
|
||||||
|
|
||||||
size_t frag_length = iterator->cur_length;
|
|
||||||
const uint8_t *frag_data = iterator->cur_data;
|
|
||||||
size_t in_frag = iterator->in_cur;
|
|
||||||
size_t new_offset = iterator->offset;
|
|
||||||
|
|
||||||
if (fragment == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
size_t frag_remaining = frag_length - in_frag;
|
|
||||||
const uint8_t * ptr = memchr (frag_data + in_frag, c, frag_remaining);
|
|
||||||
if (ptr != NULL)
|
|
||||||
{
|
|
||||||
iterator->offset = (ptr - frag_data) - in_frag + new_offset;
|
|
||||||
iterator->fragment = fragment;
|
|
||||||
iterator->in_cur = ptr - frag_data;
|
|
||||||
iterator->cur_length = frag_length;
|
|
||||||
iterator->cur_data = frag_data;
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
fragment = fragment->next;
|
|
||||||
if (fragment == NULL)
|
|
||||||
return FALSE;
|
|
||||||
new_offset += frag_length - in_frag;
|
|
||||||
in_frag = 0;
|
|
||||||
frag_length = fragment->buf_length;
|
|
||||||
frag_data = protobuf_c_data_buffer_fragment_start (fragment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* protobuf_c_data_buffer_iterator_skip:
|
|
||||||
* @iterator: to advance.
|
|
||||||
* @max_length: maximum number of bytes to skip forward.
|
|
||||||
*
|
|
||||||
* Advance an iterator forward in the buffer,
|
|
||||||
* returning the number of bytes skipped.
|
|
||||||
*
|
|
||||||
* returns: number of bytes skipped forward.
|
|
||||||
*/
|
|
||||||
size_t
|
|
||||||
protobuf_c_data_buffer_iterator_skip (ProtobufCDataBufferIterator *iterator,
|
|
||||||
size_t max_length)
|
|
||||||
{
|
|
||||||
ProtobufCDataBufferFragment *fragment = iterator->fragment;
|
|
||||||
|
|
||||||
size_t frag_length = iterator->cur_length;
|
|
||||||
const uint8_t *frag_data = iterator->cur_data;
|
|
||||||
size_t in_frag = iterator->in_cur;
|
|
||||||
|
|
||||||
size_t out_remaining = max_length;
|
|
||||||
|
|
||||||
while (fragment != NULL)
|
|
||||||
{
|
|
||||||
size_t frag_remaining = frag_length - in_frag;
|
|
||||||
if (out_remaining <= frag_remaining)
|
|
||||||
{
|
|
||||||
in_frag += out_remaining;
|
|
||||||
out_remaining = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
out_remaining -= frag_remaining;
|
|
||||||
|
|
||||||
fragment = fragment->next;
|
|
||||||
if (fragment != NULL)
|
|
||||||
{
|
|
||||||
frag_data = (uint8_t *) protobuf_c_data_buffer_fragment_start (fragment);
|
|
||||||
frag_length = fragment->buf_length;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
frag_data = NULL;
|
|
||||||
frag_length = 0;
|
|
||||||
}
|
|
||||||
in_frag = 0;
|
|
||||||
}
|
|
||||||
iterator->in_cur = in_frag;
|
|
||||||
iterator->fragment = fragment;
|
|
||||||
iterator->cur_length = frag_length;
|
|
||||||
iterator->cur_data = frag_data;
|
|
||||||
iterator->offset += max_length - out_remaining;
|
|
||||||
return max_length - out_remaining;
|
|
||||||
}
|
|
||||||
|
@ -45,6 +45,8 @@ char *protobuf_c_data_buffer_parse_string0 (ProtobufCDataBuffer *buf
|
|||||||
int protobuf_c_data_buffer_peek_char (const ProtobufCDataBuffer *buffer);
|
int protobuf_c_data_buffer_peek_char (const ProtobufCDataBuffer *buffer);
|
||||||
int protobuf_c_data_buffer_read_char (ProtobufCDataBuffer *buffer);
|
int protobuf_c_data_buffer_read_char (ProtobufCDataBuffer *buffer);
|
||||||
|
|
||||||
|
int protobuf_c_data_buffer_index_of(ProtobufCDataBuffer *buffer,
|
||||||
|
char char_to_find);
|
||||||
/*
|
/*
|
||||||
* Appending to the buffer.
|
* Appending to the buffer.
|
||||||
*/
|
*/
|
||||||
@ -72,13 +74,6 @@ void protobuf_c_data_buffer_append_string0 (ProtobufCDataBuffer *buf
|
|||||||
const char *string);
|
const char *string);
|
||||||
|
|
||||||
|
|
||||||
void protobuf_c_data_buffer_printf (ProtobufCDataBuffer *buffer,
|
|
||||||
const char *format,
|
|
||||||
...) PROTOBUF_C_GNUC_PRINTF(2,3);
|
|
||||||
void protobuf_c_data_buffer_vprintf (ProtobufCDataBuffer *buffer,
|
|
||||||
const char *format,
|
|
||||||
va_list args);
|
|
||||||
|
|
||||||
/* Take all the contents from src and append
|
/* Take all the contents from src and append
|
||||||
* them to dst, leaving src empty.
|
* them to dst, leaving src empty.
|
||||||
*/
|
*/
|
||||||
@ -99,16 +94,6 @@ int protobuf_c_data_buffer_writev_len (ProtobufCDataBuffer *
|
|||||||
int protobuf_c_data_buffer_read_in_fd (ProtobufCDataBuffer *write_to,
|
int protobuf_c_data_buffer_read_in_fd (ProtobufCDataBuffer *write_to,
|
||||||
int read_from);
|
int read_from);
|
||||||
|
|
||||||
/*
|
|
||||||
* Scanning the buffer.
|
|
||||||
*/
|
|
||||||
int protobuf_c_data_buffer_index_of (ProtobufCDataBuffer *buffer,
|
|
||||||
char char_to_find);
|
|
||||||
int protobuf_c_data_buffer_str_index_of (ProtobufCDataBuffer *buffer,
|
|
||||||
const char *str_to_find);
|
|
||||||
int protobuf_c_data_buffer_polystr_index_of (ProtobufCDataBuffer *buffer,
|
|
||||||
char **strings);
|
|
||||||
|
|
||||||
/* This deallocates memory used by the buffer-- you are responsible
|
/* This deallocates memory used by the buffer-- you are responsible
|
||||||
* for the allocation and deallocation of the ProtobufCDataBuffer itself. */
|
* for the allocation and deallocation of the ProtobufCDataBuffer itself. */
|
||||||
void protobuf_c_data_buffer_destruct (ProtobufCDataBuffer *to_destroy);
|
void protobuf_c_data_buffer_destruct (ProtobufCDataBuffer *to_destroy);
|
||||||
@ -116,32 +101,4 @@ void protobuf_c_data_buffer_destruct (ProtobufCDataBuffer *to_
|
|||||||
/* Free all unused buffer fragments. */
|
/* Free all unused buffer fragments. */
|
||||||
void protobuf_c_data_buffer_cleanup_recycling_bin ();
|
void protobuf_c_data_buffer_cleanup_recycling_bin ();
|
||||||
|
|
||||||
|
|
||||||
/* intended for use on the stack */
|
|
||||||
typedef struct _ProtobufCDataBufferIterator ProtobufCDataBufferIterator;
|
|
||||||
struct _ProtobufCDataBufferIterator
|
|
||||||
{
|
|
||||||
ProtobufCDataBufferFragment *fragment;
|
|
||||||
size_t in_cur;
|
|
||||||
size_t cur_length;
|
|
||||||
const uint8_t *cur_data;
|
|
||||||
size_t offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define protobuf_c_data_buffer_iterator_offset(iterator) ((iterator)->offset)
|
|
||||||
void protobuf_c_data_buffer_iterator_construct (ProtobufCDataBufferIterator *iterator,
|
|
||||||
ProtobufCDataBuffer *to_iterate);
|
|
||||||
unsigned protobuf_c_data_buffer_iterator_peek (ProtobufCDataBufferIterator *iterator,
|
|
||||||
void *out,
|
|
||||||
unsigned max_length);
|
|
||||||
unsigned protobuf_c_data_buffer_iterator_read (ProtobufCDataBufferIterator *iterator,
|
|
||||||
void *out,
|
|
||||||
unsigned max_length);
|
|
||||||
unsigned protobuf_c_data_buffer_iterator_skip (ProtobufCDataBufferIterator *iterator,
|
|
||||||
unsigned max_length);
|
|
||||||
protobuf_c_boolean protobuf_c_data_buffer_iterator_find_char (ProtobufCDataBufferIterator *iterator,
|
|
||||||
char c);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "protobuf-c-dispatch.h"
|
#include "protobuf-c-dispatch.h"
|
||||||
#include "gskrbtreemacros.h"
|
#include "gskrbtreemacros.h"
|
||||||
|
#include "gsklistmacros.h"
|
||||||
|
|
||||||
#define protobuf_c_assert(condition) assert(condition)
|
#define protobuf_c_assert(condition) assert(condition)
|
||||||
|
|
||||||
@ -70,6 +71,16 @@ struct _ProtobufCDispatchTimer
|
|||||||
void *func_data;
|
void *func_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _ProtobufCDispatchIdle
|
||||||
|
{
|
||||||
|
RealDispatch *dispatch;
|
||||||
|
|
||||||
|
ProtobufCDispatchIdle *prev, *next;
|
||||||
|
|
||||||
|
/* user callback */
|
||||||
|
ProtobufCDispatchIdleFunc func;
|
||||||
|
void *func_data;
|
||||||
|
};
|
||||||
/* Define the tree of timers, as per gskrbtreemacros.h */
|
/* Define the tree of timers, as per gskrbtreemacros.h */
|
||||||
#define TIMER_GET_IS_RED(n) ((n)->is_red)
|
#define TIMER_GET_IS_RED(n) ((n)->is_red)
|
||||||
#define TIMER_SET_IS_RED(n,v) ((n)->is_red = (v))
|
#define TIMER_SET_IS_RED(n,v) ((n)->is_red = (v))
|
||||||
@ -87,6 +98,10 @@ struct _ProtobufCDispatchTimer
|
|||||||
parent, left, right, \
|
parent, left, right, \
|
||||||
TIMERS_COMPARE
|
TIMERS_COMPARE
|
||||||
|
|
||||||
|
/* declare the idle-handler list */
|
||||||
|
#define GET_IDLE_LIST(d) \
|
||||||
|
ProtobufCDispatchIdle *, d->first_idle, d->last_idle, prev, next
|
||||||
|
|
||||||
/* Create or destroy a Dispatch */
|
/* Create or destroy a Dispatch */
|
||||||
ProtobufCDispatch *protobuf_c_dispatch_new (ProtobufCAllocator *allocator)
|
ProtobufCDispatch *protobuf_c_dispatch_new (ProtobufCAllocator *allocator)
|
||||||
{
|
{
|
||||||
@ -114,6 +129,13 @@ protobuf_c_dispatch_free(ProtobufCDispatch *dispatch)
|
|||||||
FREE (d);
|
FREE (d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProtobufCAllocator *
|
||||||
|
protobuf_c_dispatch_peek_allocator (ProtobufCDispatch *dispatch)
|
||||||
|
{
|
||||||
|
RealDispatch *d = (RealDispatch *) dispatch;
|
||||||
|
return d->allocator;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
enlarge_fd_map (RealDispatch *d,
|
enlarge_fd_map (RealDispatch *d,
|
||||||
unsigned fd)
|
unsigned fd)
|
||||||
@ -550,3 +572,35 @@ void protobuf_c_dispatch_remove_timer (ProtobufCDispatchTimer *timer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ProtobufCDispatchIdle *
|
||||||
|
protobuf_c_dispatch_add_idle (ProtobufCDispatch *dispatch,
|
||||||
|
ProtobufCDispatchIdleFunc func,
|
||||||
|
void *func_data)
|
||||||
|
{
|
||||||
|
RealDispatch *d = (RealDispatch *) dispatch;
|
||||||
|
ProtobufCDispatchIdle *rv;
|
||||||
|
if (d->recycled_idles != NULL)
|
||||||
|
{
|
||||||
|
rv = d->recycled_idles;
|
||||||
|
d->recycled_idles = rv->next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ProtobufCAllocator *allocator = d->allocator;
|
||||||
|
rv = ALLOC (sizeof (ProtobufCDispatchIdle));
|
||||||
|
}
|
||||||
|
GSK_LIST_APPEND (GET_IDLE_LIST (d), rv);
|
||||||
|
rv->func = func;
|
||||||
|
rv->func_data = func_data;
|
||||||
|
rv->dispatch = d;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
protobuf_c_dispatch_remove_idle (ProtobufCDispatchIdle *idle)
|
||||||
|
{
|
||||||
|
RealDispatch *d = idle->dispatch;
|
||||||
|
GSK_LIST_REMOVE (GET_IDLE_LIST (d), idle);
|
||||||
|
idle->next = d->recycled_idles;
|
||||||
|
d->recycled_idles = idle;
|
||||||
|
}
|
||||||
|
@ -34,7 +34,8 @@ typedef enum
|
|||||||
PROTOBUF_C_CLIENT_STATE_CONNECTING,
|
PROTOBUF_C_CLIENT_STATE_CONNECTING,
|
||||||
PROTOBUF_C_CLIENT_STATE_CONNECTED,
|
PROTOBUF_C_CLIENT_STATE_CONNECTED,
|
||||||
PROTOBUF_C_CLIENT_STATE_FAILED_WAITING,
|
PROTOBUF_C_CLIENT_STATE_FAILED_WAITING,
|
||||||
PROTOBUF_C_CLIENT_STATE_FAILED /* if no autoretry */
|
PROTOBUF_C_CLIENT_STATE_FAILED, /* if no autoretry */
|
||||||
|
PROTOBUF_C_CLIENT_STATE_DESTROYED
|
||||||
} ProtobufC_RPC_ClientState;
|
} ProtobufC_RPC_ClientState;
|
||||||
|
|
||||||
typedef struct _Closure Closure;
|
typedef struct _Closure Closure;
|
||||||
@ -68,18 +69,19 @@ struct _ProtobufC_RPC_Client
|
|||||||
} init;
|
} init;
|
||||||
struct {
|
struct {
|
||||||
protobuf_c_boolean pending;
|
protobuf_c_boolean pending;
|
||||||
|
protobuf_c_boolean destroyed_while_pending;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
} name_lookup;
|
} name_lookup;
|
||||||
struct {
|
|
||||||
ProtobufCDispatchTimer *timer;
|
|
||||||
char *error_message;
|
|
||||||
} failed_waiting;
|
|
||||||
struct {
|
struct {
|
||||||
unsigned closures_alloced;
|
unsigned closures_alloced;
|
||||||
unsigned first_free_request_id;
|
unsigned first_free_request_id;
|
||||||
/* indexed by (request_id-1) */
|
/* indexed by (request_id-1) */
|
||||||
Closure *closures;
|
Closure *closures;
|
||||||
} connected;
|
} connected;
|
||||||
|
struct {
|
||||||
|
ProtobufCDispatchTimer *timer;
|
||||||
|
char *error_message;
|
||||||
|
} failed_waiting;
|
||||||
struct {
|
struct {
|
||||||
char *error_message;
|
char *error_message;
|
||||||
} failed;
|
} failed;
|
||||||
@ -87,6 +89,7 @@ struct _ProtobufC_RPC_Client
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void begin_name_lookup (ProtobufC_RPC_Client *client);
|
static void begin_name_lookup (ProtobufC_RPC_Client *client);
|
||||||
|
static void destroy_client_rpc (ProtobufCService *service);
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -132,6 +135,7 @@ client_failed (ProtobufC_RPC_Client *client,
|
|||||||
case PROTOBUF_C_CLIENT_STATE_INIT:
|
case PROTOBUF_C_CLIENT_STATE_INIT:
|
||||||
case PROTOBUF_C_CLIENT_STATE_FAILED_WAITING:
|
case PROTOBUF_C_CLIENT_STATE_FAILED_WAITING:
|
||||||
case PROTOBUF_C_CLIENT_STATE_FAILED:
|
case PROTOBUF_C_CLIENT_STATE_FAILED:
|
||||||
|
case PROTOBUF_C_CLIENT_STATE_DESTROYED:
|
||||||
protobuf_c_assert (FALSE);
|
protobuf_c_assert (FALSE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -292,6 +296,11 @@ handle_name_lookup_success (const uint8_t *address,
|
|||||||
protobuf_c_assert (client->state == PROTOBUF_C_CLIENT_STATE_NAME_LOOKUP);
|
protobuf_c_assert (client->state == PROTOBUF_C_CLIENT_STATE_NAME_LOOKUP);
|
||||||
protobuf_c_assert (client->info.name_lookup.pending);
|
protobuf_c_assert (client->info.name_lookup.pending);
|
||||||
client->info.name_lookup.pending = 0;
|
client->info.name_lookup.pending = 0;
|
||||||
|
if (client->info.name_lookup.destroyed_while_pending)
|
||||||
|
{
|
||||||
|
destroy_client_rpc (&client->base_service);
|
||||||
|
return;
|
||||||
|
}
|
||||||
addr.sin_family = PF_INET;
|
addr.sin_family = PF_INET;
|
||||||
memcpy (&addr.sin_addr, address, 4);
|
memcpy (&addr.sin_addr, address, 4);
|
||||||
addr.sin_port = htons (client->info.name_lookup.port);
|
addr.sin_port = htons (client->info.name_lookup.port);
|
||||||
@ -306,6 +315,11 @@ handle_name_lookup_failure (const char *error_message,
|
|||||||
protobuf_c_assert (client->state == PROTOBUF_C_CLIENT_STATE_NAME_LOOKUP);
|
protobuf_c_assert (client->state == PROTOBUF_C_CLIENT_STATE_NAME_LOOKUP);
|
||||||
protobuf_c_assert (client->info.name_lookup.pending);
|
protobuf_c_assert (client->info.name_lookup.pending);
|
||||||
client->info.name_lookup.pending = 0;
|
client->info.name_lookup.pending = 0;
|
||||||
|
if (client->info.name_lookup.destroyed_while_pending)
|
||||||
|
{
|
||||||
|
destroy_client_rpc (&client->base_service);
|
||||||
|
return;
|
||||||
|
}
|
||||||
client_failed (client, "name lookup failed (for name from %s): %s", client->name, error_message);
|
client_failed (client, "name lookup failed (for name from %s): %s", client->name, error_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,6 +362,7 @@ begin_name_lookup (ProtobufC_RPC_Client *client)
|
|||||||
port = atoi (colon + 1);
|
port = atoi (colon + 1);
|
||||||
|
|
||||||
client->info.name_lookup.pending = 1;
|
client->info.name_lookup.pending = 1;
|
||||||
|
client->info.name_lookup.destroyed_while_pending = 0;
|
||||||
client->info.name_lookup.port = port;
|
client->info.name_lookup.port = port;
|
||||||
client->resolver (client->dispatch,
|
client->resolver (client->dispatch,
|
||||||
host,
|
host,
|
||||||
@ -521,16 +536,50 @@ handle_client_fd_events (int fd,
|
|||||||
{
|
{
|
||||||
uint32_t header[3];
|
uint32_t header[3];
|
||||||
unsigned service_index, message_length, request_id;
|
unsigned service_index, message_length, request_id;
|
||||||
|
Closure *closure;
|
||||||
|
uint8_t *packed_data;
|
||||||
|
ProtobufCMessage *msg;
|
||||||
protobuf_c_data_buffer_peek (&client->incoming, header, sizeof (header));
|
protobuf_c_data_buffer_peek (&client->incoming, header, sizeof (header));
|
||||||
service_index = uint32_from_le (header[0]);
|
service_index = uint32_from_le (header[0]);
|
||||||
message_length = uint32_from_le (header[1]);
|
message_length = uint32_from_le (header[1]);
|
||||||
request_id = header[2]; /* already native-endian */
|
request_id = header[2]; /* already native-endian */
|
||||||
|
|
||||||
if (12 + message_length > client.incoming.size)
|
if (12 + message_length > client->incoming.size)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* lookup request by id */
|
/* lookup request by id */
|
||||||
...
|
if (request_id >= client->info.connected.closures_alloced
|
||||||
|
|| request_id == 0
|
||||||
|
|| client->info.connected.closures[request_id-1].response_type == NULL)
|
||||||
|
{
|
||||||
|
client_failed (client, "bad request-id in response from server");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
closure = client->info.connected.closures + (request_id - 1);
|
||||||
|
|
||||||
|
/* read message and unpack */
|
||||||
|
protobuf_c_data_buffer_discard (&client->incoming, 12);
|
||||||
|
packed_data = client->allocator->alloc (client->allocator, message_length);
|
||||||
|
protobuf_c_data_buffer_read (&client->incoming, packed_data, message_length);
|
||||||
|
|
||||||
|
/* TODO: use fast temporary allocator */
|
||||||
|
msg = protobuf_c_message_unpack (closure->response_type,
|
||||||
|
client->allocator,
|
||||||
|
message_length,
|
||||||
|
packed_data);
|
||||||
|
if (msg == NULL)
|
||||||
|
{
|
||||||
|
client_failed (client, "failed to unpack message");
|
||||||
|
client->allocator->free (client->allocator, packed_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* invoke closure */
|
||||||
|
closure->closure (msg, closure->closure_data);
|
||||||
|
|
||||||
|
/* clean up */
|
||||||
|
protobuf_c_message_free_unpacked (msg, client->allocator);
|
||||||
|
client->allocator->free (client->allocator, packed_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -577,7 +626,8 @@ invoke_client_rpc (ProtobufCService *service,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case PROTOBUF_C_CLIENT_STATE_FAILED_WAITING:
|
case PROTOBUF_C_CLIENT_STATE_FAILED_WAITING:
|
||||||
case PROTOBUF_C_CLIENT_STATE_FAILED: /* if no autoretry */
|
case PROTOBUF_C_CLIENT_STATE_FAILED:
|
||||||
|
case PROTOBUF_C_CLIENT_STATE_DESTROYED:
|
||||||
closure (NULL, closure_data);
|
closure (NULL, closure_data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -587,7 +637,55 @@ static void
|
|||||||
destroy_client_rpc (ProtobufCService *service)
|
destroy_client_rpc (ProtobufCService *service)
|
||||||
{
|
{
|
||||||
ProtobufC_RPC_Client *client = (ProtobufC_RPC_Client *) service;
|
ProtobufC_RPC_Client *client = (ProtobufC_RPC_Client *) service;
|
||||||
...
|
ProtobufC_RPC_ClientState state = client->state;
|
||||||
|
unsigned i;
|
||||||
|
unsigned n_closures = 0;
|
||||||
|
Closure *closures = NULL;
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case PROTOBUF_C_CLIENT_STATE_INIT:
|
||||||
|
protobuf_c_dispatch_remove_idle (client->info.init.idle);
|
||||||
|
break;
|
||||||
|
case PROTOBUF_C_CLIENT_STATE_NAME_LOOKUP:
|
||||||
|
if (client->info.name_lookup.pending)
|
||||||
|
{
|
||||||
|
client->info.name_lookup.destroyed_while_pending = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PROTOBUF_C_CLIENT_STATE_CONNECTING:
|
||||||
|
break;
|
||||||
|
case PROTOBUF_C_CLIENT_STATE_CONNECTED:
|
||||||
|
n_closures = client->info.connected.closures_alloced;
|
||||||
|
closures = client->info.connected.closures;
|
||||||
|
break;
|
||||||
|
case PROTOBUF_C_CLIENT_STATE_FAILED_WAITING:
|
||||||
|
protobuf_c_dispatch_remove_timer (client->info.failed_waiting.timer);
|
||||||
|
client->allocator->free (client->allocator, client->info.failed_waiting.error_message);
|
||||||
|
break;
|
||||||
|
case PROTOBUF_C_CLIENT_STATE_FAILED:
|
||||||
|
client->allocator->free (client->allocator, client->info.failed.error_message);
|
||||||
|
break;
|
||||||
|
case PROTOBUF_C_CLIENT_STATE_DESTROYED:
|
||||||
|
protobuf_c_assert (0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (client->fd >= 0)
|
||||||
|
{
|
||||||
|
protobuf_c_dispatch_close_fd (client->dispatch, client->fd);
|
||||||
|
client->fd = -1;
|
||||||
|
}
|
||||||
|
protobuf_c_data_buffer_clear (&client->incoming);
|
||||||
|
protobuf_c_data_buffer_clear (&client->outgoing);
|
||||||
|
client->state = PROTOBUF_C_CLIENT_STATE_DESTROYED;
|
||||||
|
|
||||||
|
/* free closures only once we are in the destroyed state */
|
||||||
|
for (i = 0; i < n_closures; i++)
|
||||||
|
closures[i].closure (NULL, closures[i].closure_data);
|
||||||
|
if (closures)
|
||||||
|
client->allocator->free (client->allocator, closures);
|
||||||
|
|
||||||
|
client->allocator->free (client->allocator, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtobufCService *protobuf_c_rpc_client_new (ProtobufC_RPC_AddressType type,
|
ProtobufCService *protobuf_c_rpc_client_new (ProtobufC_RPC_AddressType type,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user