This is not final version, some things doesn't work yet.
lib_LIBRARIES += forb
forb_SOURCES = forb.c cdr.c sha1.c uuid.c iop.c proto.c syncobj.c \
- request.c executor.c object.c peer.c port.c
+ request.c executor.c object.c peer.c port.c refcnt.c
forb_CLIENT_IDL = types.idl iop-idl.idl
to_forb_subdir=$(1)->forb/$(strip $(1))
}
forb_proto_send(peer, codec);
err:
- ;
+ forb_peer_put(peer);
}
peer = forb_peer_find(forb, &server_id);
if (peer) {
/* TODO: Update last hello receive time */
+ forb_peer_put(peer);
} else {
/* New peer discovered */
/* char str[100]; */
/* printf("New peer %s discovered port %p\n", */
/* forb_server_id_to_string(str, &server_id, sizeof(str)), port); */
- peer = forb_malloc(sizeof(*peer));
- peer->server_id = server_id;
- peer->port = port;
- peer->addr = addr;
- forb_peer_insert(forb, peer);
-
+ peer = forb_peer_new();
+ if (peer) {
+ peer->server_id = server_id;
+ peer->port = port;
+ peer->addr = addr;
+ forb_peer_insert(forb, peer);
+ forb_peer_put(peer);
+ }
/* Broadcast our hello packet now */
forb_syncobj_signal(&port->hello);
}
--- /dev/null
+#ifndef FORB_MISC_H
+#define FORB_MISC_H
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+/**
+ * Cast a member of a structure out to the containing structure.
+ *
+ * @param ptr the pointer to the member.
+ * @param type the type of the container struct this is embedded in.
+ * @param member the name of the member within the struct.
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+
+#endif
#include "peer.h"
+#include "misc.h"
+#include "proto.h"
GAVL_CUST_NODE_INT_IMP(forb_peer_nolock,/* cust_prefix */
forb_t, /* cust_root_t */
forb_server_id_cmp);/* cust_cmp_fnc */
+
+forb_peer_t *
+forb_peer_new(void)
+{
+ forb_peer_t *peer;
+
+ peer = forb_malloc(sizeof(*peer));
+ if (peer) {
+ forb_ref_init(&peer->ref);
+ }
+ return peer;
+}
+
+void
+forb_peer_release(forb_ref_t *ref)
+{
+ forb_peer_t *peer = container_of(ref, forb_peer_t, ref);
+ if (peer->port->proto->peer_destroy) {
+ peer->port->proto->peer_destroy(peer);
+ }
+ forb_free(peer);
+}
#include <forb/forb-internal.h>
#include "port.h"
+#include "refcnt.h"
/**
* Description of a peer. We consider peers only in one-hop
* distance. For more distant forbs, we need to use a routing table.
+ *
+ * @note This structure is reference counted. Use forb_peer_get() when
+ * you copy a pointer to peer and forb_peer_put() when the pointer is
+ * not needed.
*/
struct forb_peer {
forb_server_id server_id; /**< Server_id of the peer */
void *addr; /**< Protocol specific address of the peer */
void *proto_priv; /**< Protocol private data (e.g. info about established connection) */
gavl_node_t node; /**< Node of port's peers tree */
+ forb_ref_t ref; /**< Reference count */
};
typedef struct forb_peer forb_peer_t;
server_id, /* cust_item_key */
forb_server_id_cmp)/* cust_cmp_fnc */
+forb_peer_t *
+forb_peer_new(void);
+
+void
+forb_peer_release(forb_ref_t *ref);
+
+static inline void
+forb_peer_get(forb_peer_t *peer)
+{
+ forb_ref_get(&peer->ref);
+}
+
+static inline void
+forb_peer_put(forb_peer_t *peer)
+{
+ forb_ref_put(&peer->ref, forb_peer_release);
+}
+
static inline void
forb_peer_insert(forb_t *forb, forb_peer_t *peer)
{
fosa_mutex_lock(&forb->peer_mutex);
+ forb_peer_get(peer);
forb_peer_nolock_insert(forb, peer);
fosa_mutex_unlock(&forb->peer_mutex);
}
{
fosa_mutex_lock(&forb->peer_mutex);
forb_peer_nolock_delete(forb, peer);
+ forb_peer_put(peer);
fosa_mutex_unlock(&forb->peer_mutex);
}
+/**
+ * Finds peer with given @a server_id.
+ *
+ * @param forb
+ * @param server_id
+ *
+ * @return The found peer or NULL if no peer is found. You have to
+ * call forb_peer_put() after you finish working with the non NULL
+ * retuned value.
+ */
static inline forb_peer_t *
forb_peer_find(forb_t *forb, forb_server_id *server_id)
{
forb_peer_t *ret;
fosa_mutex_lock(&forb->peer_mutex);
ret = forb_peer_nolock_find(forb, server_id);
+ if (ret) {
+ forb_peer_get(ret);
+ }
fosa_mutex_unlock(&forb->peer_mutex);
return ret;
}
}
fosa_mutex_lock(&port->forb->peer_mutex);
+ /* FIXME: Is gavl_cust_for_each() deletion safe? What about
+ * recursive locking of mutex. */
+#warning Delete during GAVL traversal is problbly not correct.
gavl_cust_for_each(forb_peer_nolock, forb, peer) {
if (peer->port == port) {
- if (port->proto->peer_destroy) {
- port->proto->peer_destroy(peer);
- }
- /* TODO: Reference counting */
- forb_free(peer);
+ forb_peer_delete(forb, peer);
}
}
fosa_mutex_unlock(&port->forb->peer_mutex);
--- /dev/null
+/**
+ * @file refcnt.c
+ * @author Michal Sojka <sojkam1@fel.cvut.cz>
+ * @date Wed Oct 1 09:23:40 2008
+ *
+ * @brief Atomic reference counting operations.
+ *
+ * @note: To provide portable atomicity, we use GCC's builtin
+ * functions introduced in GCC 4.1.
+ *
+ */
+#include "refcnt.h"
+
+void forb_ref_set(struct forb_ref *ref, int num)
+{
+ ref->refcount = num;
+}
+
+void forb_ref_init(struct forb_ref *ref)
+{
+ forb_ref_set(ref, 1);
+}
+
+void forb_ref_get(struct forb_ref *ref)
+{
+ __sync_add_and_fetch(&ref->refcount, 1);
+}
+
+int forb_ref_put(struct forb_ref *ref, void (*release) (struct forb_ref *ref))
+{
+ if (__sync_add_and_fetch(&ref->refcount, -1) == 0) {
+ release(ref);
+ return 1;
+ }
+ return 0;
+}
--- /dev/null
+#ifndef FORB_REFCNT_H
+#define FORB_REFCNT_H
+
+struct forb_ref {
+ unsigned refcount;
+};
+
+typedef struct forb_ref forb_ref_t;
+
+void forb_ref_set(struct forb_ref *ref, int num);
+void forb_ref_init(struct forb_ref *ref);
+void forb_ref_get(struct forb_ref *ref);
+int forb_ref_put(struct forb_ref *ref, void (*release) (struct forb_ref *ref));
+
+
+#endif