summaryrefslogtreecommitdiffstats
path: root/libglusterfs/src/stack.h
diff options
context:
space:
mode:
Diffstat (limited to 'libglusterfs/src/stack.h')
-rw-r--r--libglusterfs/src/stack.h266
1 files changed, 266 insertions, 0 deletions
diff --git a/libglusterfs/src/stack.h b/libglusterfs/src/stack.h
new file mode 100644
index 00000000000..f014a4a27ac
--- /dev/null
+++ b/libglusterfs/src/stack.h
@@ -0,0 +1,266 @@
+/*
+ Copyright (c) 2006, 2007, 2008 Z RESEARCH, Inc. <http://www.zresearch.com>
+ This file is part of GlusterFS.
+
+ GlusterFS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ GlusterFS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ This file defines MACROS and static inlines used to emulate a function
+ call over asynchronous communication with remote server
+*/
+
+#ifndef _STACK_H
+#define _STACK_H
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+struct _call_stack_t;
+typedef struct _call_stack_t call_stack_t;
+struct _call_frame_t;
+typedef struct _call_frame_t call_frame_t;
+struct _call_pool_t;
+typedef struct _call_pool_t call_pool_t;
+
+#include "xlator.h"
+#include "dict.h"
+#include "list.h"
+#include "common-utils.h"
+
+
+typedef int32_t (*ret_fn_t) (call_frame_t *frame,
+ call_frame_t *prev_frame,
+ xlator_t *this,
+ int32_t op_ret,
+ int32_t op_errno,
+ ...);
+
+struct _call_pool_t {
+ union {
+ struct list_head all_frames;
+ struct {
+ call_stack_t *next_call;
+ call_stack_t *prev_call;
+ } all_stacks;
+ };
+ int64_t cnt;
+ gf_lock_t lock;
+};
+
+struct _call_frame_t {
+ call_stack_t *root; /* stack root */
+ call_frame_t *parent; /* previous BP */
+ call_frame_t *next;
+ call_frame_t *prev; /* maintainence list */
+ void *local; /* local variables */
+ xlator_t *this; /* implicit object */
+ ret_fn_t ret; /* op_return address */
+ int32_t ref_count;
+ gf_lock_t lock;
+ void *cookie; /* unique cookie */
+};
+
+struct _call_stack_t {
+ union {
+ struct list_head all_frames;
+ struct {
+ call_stack_t *next_call;
+ call_stack_t *prev_call;
+ };
+ };
+ call_pool_t *pool;
+ void *trans;
+ uint64_t unique;
+ void *state; /* pointer to request state */
+ uid_t uid;
+ gid_t gid;
+ pid_t pid;
+ call_frame_t frames;
+ dict_t *req_refs;
+ dict_t *rsp_refs;
+
+ int32_t op;
+ int8_t type;
+};
+
+
+static inline void
+FRAME_DESTROY (call_frame_t *frame)
+{
+ if (frame->next)
+ frame->next->prev = frame->prev;
+ if (frame->prev)
+ frame->prev->next = frame->next;
+ if (frame->local)
+ FREE (frame->local);
+ LOCK_DESTROY (&frame->lock);
+ FREE (frame);
+}
+
+
+static inline void
+STACK_DESTROY (call_stack_t *stack)
+{
+ LOCK (&stack->pool->lock);
+ {
+ list_del_init (&stack->all_frames);
+ stack->pool->cnt--;
+ }
+ UNLOCK (&stack->pool->lock);
+
+ if (stack->frames.local)
+ FREE (stack->frames.local);
+
+ LOCK_DESTROY (&stack->frames.lock);
+
+ while (stack->frames.next) {
+ FRAME_DESTROY (stack->frames.next);
+ }
+ FREE (stack);
+}
+
+
+#define cbk(x) cbk_##x
+
+
+/* make a call */
+#define STACK_WIND(frame, rfn, obj, fn, params ...) \
+ do { \
+ call_frame_t *_new = NULL; \
+ \
+ _new = CALLOC (1, sizeof (call_frame_t)); \
+ ERR_ABORT (_new); \
+ typeof(fn##_cbk) tmp_cbk = rfn; \
+ _new->root = frame->root; \
+ _new->next = frame->root->frames.next; \
+ _new->prev = &frame->root->frames; \
+ if (frame->root->frames.next) \
+ frame->root->frames.next->prev = _new; \
+ frame->root->frames.next = _new; \
+ _new->this = obj; \
+ _new->ret = (ret_fn_t) tmp_cbk; \
+ _new->parent = frame; \
+ _new->cookie = _new; \
+ LOCK_INIT (&_new->lock); \
+ frame->ref_count++; \
+ \
+ fn (_new, obj, params); \
+ } while (0)
+
+
+/* make a call with a cookie */
+#define STACK_WIND_COOKIE(frame, rfn, cky, obj, fn, params ...) \
+ do { \
+ call_frame_t *_new = CALLOC (1, \
+ sizeof (call_frame_t)); \
+ ERR_ABORT (_new); \
+ typeof(fn##_cbk) tmp_cbk = rfn; \
+ _new->root = frame->root; \
+ _new->next = frame->root->frames.next; \
+ _new->prev = &frame->root->frames; \
+ if (frame->root->frames.next) \
+ frame->root->frames.next->prev = _new; \
+ frame->root->frames.next = _new; \
+ _new->this = obj; \
+ _new->ret = (ret_fn_t) tmp_cbk; \
+ _new->parent = frame; \
+ _new->cookie = cky; \
+ LOCK_INIT (&_new->lock); \
+ frame->ref_count++; \
+ fn##_cbk = rfn; \
+ \
+ fn (_new, obj, params); \
+ } while (0)
+
+
+/* return from function */
+#define STACK_UNWIND(frame, params ...) \
+ do { \
+ ret_fn_t fn = frame->ret; \
+ call_frame_t *_parent = frame->parent; \
+ _parent->ref_count--; \
+ fn (_parent, frame->cookie, _parent->this, params); \
+ } while (0)
+
+
+static inline call_frame_t *
+copy_frame (call_frame_t *frame)
+{
+ call_stack_t *newstack = NULL;
+ call_stack_t *oldstack = NULL;
+
+ if (!frame) {
+ return NULL;
+ }
+
+ newstack = (void *) CALLOC (1, sizeof (*newstack));
+ oldstack = frame->root;
+
+ newstack->uid = oldstack->uid;
+ newstack->gid = oldstack->gid;
+ newstack->pid = oldstack->pid;
+ newstack->unique = oldstack->unique;
+
+ newstack->frames.this = frame->this;
+ newstack->frames.root = newstack;
+ newstack->pool = oldstack->pool;
+
+ LOCK_INIT (&newstack->frames.lock);
+
+ LOCK (&oldstack->pool->lock);
+ {
+ list_add (&newstack->all_frames, &oldstack->all_frames);
+ newstack->pool->cnt++;
+
+ }
+ UNLOCK (&oldstack->pool->lock);
+
+ return &newstack->frames;
+}
+
+static inline call_frame_t *
+create_frame (xlator_t *xl, call_pool_t *pool)
+{
+ call_stack_t *stack = NULL;
+
+ if (!xl || !pool) {
+ return NULL;
+ }
+
+ stack = CALLOC (1, sizeof (*stack));
+ if (!stack)
+ return NULL;
+
+ stack->pool = pool;
+ stack->frames.root = stack;
+ stack->frames.this = xl;
+
+ LOCK (&pool->lock);
+ {
+ list_add (&stack->all_frames, &pool->all_frames);
+ pool->cnt++;
+ }
+ UNLOCK (&pool->lock);
+
+ LOCK_INIT (&stack->frames.lock);
+
+ return &stack->frames;
+}
+
+
+#endif /* _STACK_H */