Skip to content

Commit

Permalink
Introduce new refcounts infrastructure.
Browse files Browse the repository at this point in the history
  • Loading branch information
vstakhov committed Feb 12, 2014
1 parent 3f5ef95 commit fd79189
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 88 deletions.
8 changes: 4 additions & 4 deletions include/rdns.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,10 @@ void rdns_resolver_register_plugin (struct rdns_resolver *resolver,
bool rdns_resolver_init (struct rdns_resolver *resolver);

/**
* Destroy resolver and free all associated structures
* Decrease refcount for a resolver and free it if refcount is 0
* @param resolver
*/
void rdns_resolver_destroy (struct rdns_resolver *resolver);
void rdns_resolver_release (struct rdns_resolver *resolver);

/**
* Make a DNS request
Expand Down Expand Up @@ -232,13 +232,13 @@ const char *rdns_strtype (enum rdns_request_type type);
* @param req
* @return
*/
struct rdns_request* rdns_request_ref (struct rdns_request *req);
struct rdns_request* rdns_request_retain (struct rdns_request *req);

/**
* Decrease refcount for a request and free it if refcount is 0
* @param req
*/
void rdns_request_unref (struct rdns_request *req);
void rdns_request_release (struct rdns_request *req);

/*
* Private functions used by async libraries as callbacks
Expand Down
6 changes: 4 additions & 2 deletions src/dns_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "utlist.h"
#include "rdns.h"
#include "upstream.h"
#include "ref.h"

#define DNS_DEBUG(...) do { fprintf (stderr, __VA_ARGS__); fprintf (stderr, "\n"); } while (0);

Expand Down Expand Up @@ -78,7 +79,6 @@ struct rdns_request {
int id;
const char *requested_name;

int ref;
enum {
RDNS_REQUEST_NEW = 0,
RDNS_REQUEST_REGISTERED = 1,
Expand All @@ -98,6 +98,7 @@ struct rdns_request {
void *network_plugin_data;

UT_hash_handle hh;
ref_entry_t ref;
};

/**
Expand All @@ -110,9 +111,9 @@ struct rdns_io_channel {
void *async_io; /** async opaque ptr */
struct rdns_request *requests; /**< requests in flight */
struct rdns_io_channel *prev, *next;
unsigned int ref;
bool want_reinit;
UT_hash_handle hh;
ref_entry_t ref;
};


Expand All @@ -126,6 +127,7 @@ struct rdns_resolver {

bool async_binded;
bool initialized;
ref_entry_t ref;
};

struct dns_header;
Expand Down
71 changes: 71 additions & 0 deletions src/ref.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/* Copyright (c) 2014, Vsevolod Stakhov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef REF_H_
#define REF_H_

/**
* @file ref.h
* A set of macros to handle refcounts
*/

typedef void (*ref_dtor_cb_t)(void *data);

typedef struct ref_entry_s {
unsigned int refcount;
ref_dtor_cb_t dtor;
} ref_entry_t;

#define REF_INIT(obj, dtor_cb) do { \
(obj)->ref.refcount = 0; \
(obj)->ref.dtor = (ref_dtor_cb_t)(dtor_cb); \
} while (0)

#define REF_INIT_RETAIN(obj, dtor_cb) do { \
(obj)->ref.refcount = 1; \
(obj)->ref.dtor = (ref_dtor_cb_t)(dtor_cb); \
} while (0)

#ifdef HAVE_ATOMIC
#define REF_RETAIN(obj) do { \
__sync_add_and_fetch (&(obj)->ref.refcount, 1); \
} while (0)

#define REF_RELEASE(obj) do { \
unsigned int rc = __sync_sub_and_fetch (&(obj)->ref.refcount, 1) \
if (rc == 0 && (obj)->ref.dtor) { \
(obj)->ref.dtor (obj); \
} \
} while (0)
#else
#define REF_RETAIN(obj) do { \
(obj)->ref.refcount ++; \
} while (0)

#define REF_RELEASE(obj) do { \
if (--(obj)->ref.refcount == 0 && (obj)->ref.dtor) { \
(obj)->ref.dtor (obj); \
} \
} while (0)
#endif

#endif /* REF_H_ */
59 changes: 32 additions & 27 deletions src/resolver.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,9 +268,9 @@ rdns_process_read (int fd, void *arg)
if (req != NULL) {
if (rdns_parse_reply (in, r, req, &rep)) {
UPSTREAM_OK (req->io->srv);
rdns_request_ref (req);
REF_RETAIN (req);
req->func (rep, req->arg);
rdns_request_unref (req);
REF_RELEASE (req);
}
}
}
Expand All @@ -289,9 +289,9 @@ rdns_process_timer (void *arg)
if (req->retransmits == 0) {
UPSTREAM_FAIL (req->io->srv, time (NULL));
rep = rdns_make_reply (req, DNS_RC_TIMEOUT);
rdns_request_ref (req);
REF_RETAIN (req);
req->func (rep, req->arg);
rdns_request_unref (req);
REF_RELEASE (req);

return;
}
Expand All @@ -308,9 +308,9 @@ rdns_process_timer (void *arg)
else if (r == -1) {
UPSTREAM_FAIL (req->io->srv, time (NULL));
rep = rdns_make_reply (req, DNS_RC_NETERR);
rdns_request_ref (req);
REF_RETAIN (req);
req->func (rep, req->arg);
rdns_request_unref (req);
REF_RELEASE (req);
}
else {
req->async->repeat_timer (req->async->data, req->async_event);
Expand Down Expand Up @@ -349,9 +349,9 @@ rdns_process_retransmit (int fd, void *arg)
else if (r == -1) {
UPSTREAM_FAIL (req->io->srv, time (NULL));
rep = rdns_make_reply (req, DNS_RC_NETERR);
rdns_request_ref (req);
REF_RETAIN (req);
req->func (rep, req->arg);
rdns_request_unref (req);
REF_RELEASE (req);
}
else {
req->async_event = req->async->add_timer (req->async->data,
Expand Down Expand Up @@ -391,9 +391,9 @@ rdns_make_request_full (
req->resolver = resolver;
req->func = cb;
req->arg = cbdata;
req->ref = 1;
req->reply = NULL;
req->network_plugin_data = NULL;
REF_INIT_RETAIN (req, rdns_request_free);

va_start (args, queries);
for (i = 0; i < queries; i ++) {
Expand Down Expand Up @@ -437,7 +437,7 @@ rdns_make_request_full (

if (serv == NULL) {
DNS_DEBUG ("cannot find suitable server for request");
rdns_request_unref (req);
REF_RELEASE (req);
return NULL;
}

Expand All @@ -446,7 +446,7 @@ rdns_make_request_full (
req->io = serv->cur_io_channel;
if (req->io == NULL) {
DNS_DEBUG ("cannot find suitable io channel for the server %s", serv->name);
rdns_request_unref (req);
REF_RELEASE (req);
return NULL;
}
serv->cur_io_channel = serv->cur_io_channel->next;
Expand All @@ -455,11 +455,12 @@ rdns_make_request_full (
r = rdns_send_request (req, req->io->sock, true);

if (r == -1) {
rdns_request_unref (req);
REF_RELEASE (req);
return NULL;
}

rdns_ioc_ref (req->io);
REF_RETAIN (req->io);
REF_RETAIN (req->resolver);

return req;
}
Expand Down Expand Up @@ -488,10 +489,10 @@ rdns_resolver_init (struct rdns_resolver *resolver)
ioc->resolver = resolver;
ioc->async_io = resolver->async->add_read (resolver->async->data,
ioc->sock, ioc);
ioc->ref = 1;
serv->cur_io_channel = ioc;
CDL_PREPEND (serv->io_channels, ioc);
HASH_ADD_INT (resolver->io_channels, sock, ioc);
REF_INIT_RETAIN (ioc, rdns_ioc_free);
}
}
}
Expand Down Expand Up @@ -560,18 +561,8 @@ rdns_resolver_add_server (struct rdns_resolver *resolver,
return true;
}

struct rdns_resolver *
rdns_resolver_new (void)
{
struct rdns_resolver *new;

new = calloc (1, sizeof (struct rdns_resolver));

return new;
}

void
rdns_resolver_destroy (struct rdns_resolver *resolver)
static void
rdns_resolver_free (struct rdns_resolver *resolver)
{
struct rdns_server *serv, *stmp;
struct rdns_io_channel *ioc, *itmp1, *itmp2;
Expand All @@ -587,16 +578,30 @@ rdns_resolver_destroy (struct rdns_resolver *resolver)
UPSTREAM_FOREACH_SAFE (resolver->servers, serv, stmp) {
CDL_FOREACH_SAFE (serv->io_channels, ioc, itmp1, itmp2) {
HASH_DELETE (hh, resolver->io_channels, ioc);
rdns_ioc_unref (ioc, resolver->async);
REF_RELEASE (ioc);
}
UPSTREAM_DEL (resolver->servers, serv);
free (serv->name);
free (serv);
}
}
free (resolver->async);
free (resolver);
}


struct rdns_resolver *
rdns_resolver_new (void)
{
struct rdns_resolver *new;

new = calloc (1, sizeof (struct rdns_resolver));

REF_INIT_RETAIN (new, rdns_resolver_free);

return new;
}

void
rdns_resolver_async_bind (struct rdns_resolver *resolver,
struct rdns_async_context *ctx)
Expand Down

0 comments on commit fd79189

Please sign in to comment.