summaryrefslogtreecommitdiff
path: root/res/res_odbc.c
diff options
context:
space:
mode:
authorTilghman Lesher <tilghman@meg.abyt.es>2008-05-20 16:13:48 +0000
committerTilghman Lesher <tilghman@meg.abyt.es>2008-05-20 16:13:48 +0000
commit01e2bd1e2f774158277621e90c50dbbfd21df8cc (patch)
tree18bb2c2ec8b459991afdd82c63c948900361a86e /res/res_odbc.c
parent7d2d373d6fa9163584e467abaef29cec74bdd6cb (diff)
Revert part of previous fix, and heavily comment the logic for object
destruction, for future users. (Closes issue #12677) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@117262 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res/res_odbc.c')
-rw-r--r--res/res_odbc.c68
1 files changed, 47 insertions, 21 deletions
diff --git a/res/res_odbc.c b/res/res_odbc.c
index 9103dbc3e..5e0ea4b54 100644
--- a/res/res_odbc.c
+++ b/res/res_odbc.c
@@ -483,8 +483,9 @@ struct odbc_obj *ast_odbc_request_obj(const char *name, int check)
struct ao2_iterator aoi = ao2_iterator_init(class_container, 0);
while ((class = ao2_iterator_next(&aoi))) {
- if (!strcmp(class->name, name))
+ if (!strcmp(class->name, name) && !class->delme) {
break;
+ }
ao2_ref(class, -1);
}
@@ -514,7 +515,6 @@ struct odbc_obj *ast_odbc_request_obj(const char *name, int check)
obj->parent = class;
if (odbc_obj_connect(obj) == ODBC_FAIL) {
ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
- ast_mutex_destroy(&obj->lock);
ao2_ref(obj, -1);
obj = NULL;
class->count--;
@@ -630,27 +630,10 @@ static odbc_status odbc_obj_connect(struct odbc_obj *obj)
return ODBC_SUCCESS;
}
-static int class_is_delme(void *classobj, void *arg, int flags)
-{
- struct odbc_class *class = classobj;
-
- if (class->delme) {
- struct odbc_obj *obj;
- struct ao2_iterator aoi = ao2_iterator_init(class->obj_container, OBJ_UNLINK);
- while ((obj = ao2_iterator_next(&aoi))) {
- ao2_ref(obj, -2);
- }
- return CMP_MATCH;
- }
-
- return 0;
-}
-
-
-
static int reload(void)
{
struct odbc_class *class;
+ struct odbc_obj *current;
struct ao2_iterator aoi = ao2_iterator_init(class_container, 0);
/* First, mark all to be purged */
@@ -662,7 +645,50 @@ static int reload(void)
load_odbc_config();
/* Purge remaining classes */
- ao2_callback(class_container, OBJ_NODATA | OBJ_UNLINK, class_is_delme, 0);
+
+ /* Note on how this works; this is a case of circular references, so we
+ * explicitly do NOT want to use a callback here (or we wind up in
+ * recursive hell).
+ *
+ * 1. Iterate through all the classes. Note that the classes will currently
+ * contain two classes of the same name, one of which is marked delme and
+ * will be purged when all remaining objects of the class are released, and
+ * the other, which was created above when we re-parsed the config file.
+ * 2. On each class, there is a reference held by the master container and
+ * a reference held by each connection object. There are two cases for
+ * destruction of the class, noted below. However, in all cases, all O-refs
+ * (references to objects) will first be freed, which will cause the C-refs
+ * (references to classes) to be decremented (but never to 0, because the
+ * class container still has a reference).
+ * a) If the class has outstanding objects, the C-ref by the class
+ * container will then be freed, which leaves only C-refs by any
+ * outstanding objects. When the final outstanding object is released
+ * (O-refs held by applications and dialplan functions), it will in turn
+ * free the final C-ref, causing class destruction.
+ * b) If the class has no outstanding objects, when the class container
+ * removes the final C-ref, the class will be destroyed.
+ */
+ aoi = ao2_iterator_init(class_container, 0);
+ while ((class = ao2_iterator_next(&aoi))) { /* C-ref++ (by iterator) */
+ if (class->delme) {
+ struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
+ while ((current = ao2_iterator_next(&aoi2))) { /* O-ref++ (by iterator) */
+ ao2_unlink(class->obj_container, current); /* unlink O-ref from class (reference handled implicitly) */
+ ao2_ref(current, -1); /* O-ref-- (by iterator) */
+ /* At this point, either
+ * a) there's an outstanding O-ref, or
+ * b) the object has already been destroyed.
+ */
+ }
+ ao2_unlink(class_container, class); /* unlink C-ref from container (reference handled implicitly) */
+ /* At this point, either
+ * a) there's an outstanding O-ref, which holds an outstanding C-ref, or
+ * b) the last remaining C-ref is held by the iterator, which will be
+ * destroyed in the next step.
+ */
+ }
+ ao2_ref(class, -1); /* C-ref-- (by iterator) */
+ }
return 0;
}