]> code.delx.au - pulseaudio/commitdiff
proper ref counting for more objects
authorLennart Poettering <lennart@poettering.net>
Sun, 15 Aug 2004 00:02:26 +0000 (00:02 +0000)
committerLennart Poettering <lennart@poettering.net>
Sun, 15 Aug 2004 00:02:26 +0000 (00:02 +0000)
some documentation update

git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@124 fefdeb5f-60dc-0310-8127-8f9354f1896f

24 files changed:
doxygen/doxygen.conf.in
polyp/Makefile.am
polyp/client.c
polyp/glib-mainloop.h
polyp/mainloop-api.h
polyp/mainloop-signal.h
polyp/module-protocol-stub.c
polyp/module-x11-bell.c
polyp/native-common.h
polyp/pdispatch.c
polyp/pdispatch.h
polyp/polyplib-context.c
polyp/polyplib-error.h
polyp/polyplib-subscribe.c
polyp/protocol-cli.c
polyp/protocol-esound.c
polyp/protocol-native.c
polyp/protocol-simple.c
polyp/pstream.c
polyp/pstream.h
polyp/socket-client.c
polyp/socket-client.h
polyp/socket-server.c
polyp/socket-server.h

index 78a43685d464684571b67a29517bed14b3c7c99d..7fd00c60974e9674cc73cb43075b7fd3a491ae85 100644 (file)
@@ -291,7 +291,7 @@ HIDE_SCOPE_NAMES       = NO
 # will put a list of the files that are included by a file in the documentation 
 # of that file.
 
-SHOW_INCLUDE_FILES     = YES
+SHOW_INCLUDE_FILES     = NO
 
 # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
 # is inserted in the documentation for inline members.
index 7f70ec9d4d7a0bffaaf851e636d1f9f46ee3b1ca..f2d61f7cd1784c6cdf2837568cffe3edaf33bd97 100644 (file)
@@ -124,7 +124,8 @@ polypaudio_SOURCES = idxset.c idxset.h \
                play-memchunk.c play-memchunk.h \
                autoload.c autoload.h \
                xmalloc.c xmalloc.h \
-               subscribe.h subscribe.c
+               subscribe.h subscribe.c \
+               debug.h
 
 polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS)
 polypaudio_INCLUDES = $(INCLTDL)
@@ -296,7 +297,8 @@ libpolyp_la_SOURCES = polyplib.h \
                polyplib-introspect.c polyplib-introspect.h \
                polyplib-scache.c polyplib-scache.h \
                polyplib-subscribe.c polyplib-subscribe.h \
-               cdecl.h
+               cdecl.h \
+               llist.h
 libpolyp_la_CFLAGS = $(AM_CFLAGS)
 
 libpolyp_mainloop_la_SOURCES = mainloop-api.h mainloop-api.c \
index 809f976157bcb988c9e820738df0a051457c5ee5..0cb42466a30cf1c1abdd1f8e93e69bc6e21b42c1 100644 (file)
@@ -79,4 +79,6 @@ void pa_client_rename(struct pa_client *c, const char *name) {
     assert(c);
     pa_xfree(c->name);
     c->name = pa_xstrdup(name);
+
+    pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->index);
 }
index c67e72bd11b79710903a94ca28295b427a23a2b5..1ba663fd6281b9f53152cf14e232ba824c7d6d5b 100644 (file)
@@ -24,6 +24,6 @@ void pa_glib_mainloop_free(struct pa_glib_mainloop* g);
 /** Return the abstract main loop API vtable for the GLIB main loop object */
 struct pa_mainloop_api* pa_glib_mainloop_get_api(struct pa_glib_mainloop *g);
 
-PA_C_DECL_BEGIN
+PA_C_DECL_END
 
 #endif
index 97ab6a68403c002ad4cd3bed485d24d65ca8c60a..c1f40eaeabee6f30beaee22d0c662449e4c6c2f1 100644 (file)
 
 #include "cdecl.h"
 
+/** \file
+ * 
+ * Main loop abstraction layer. Both the polypaudio core and the
+ * polypaudio client library use a main loop abstraction layer. Due to
+ * this it is possible to embed polypaudio into other
+ * applications easily. Two main loop implemenations are
+ * currently available:
+ * \li A minimal implementation based on the C library's poll() function (See \ref mainloop.h)
+ * \li A wrapper around the GLIB main loop. Use this to embed polypaudio into your GLIB/GTK+/GNOME programs (See \ref glib-mainloop.h)
+ *
+ * The structure pa_mainloop_api is used as vtable for the main loop abstraction.
+ * */
+
+
 PA_C_DECL_BEGIN
 
 /** A bitmask for IO events */
@@ -55,16 +69,28 @@ struct pa_mainloop_api {
     /** A pointer to some private, arbitrary data of the main loop implementation */
     void *userdata;
 
-    /* IO sources */
+    /** Create a new IO event source object */
     struct pa_io_event* (*io_new)(struct pa_mainloop_api*a, int fd, enum pa_io_event_flags events, void (*callback) (struct pa_mainloop_api*a, struct pa_io_event* e, int fd, enum pa_io_event_flags events, void *userdata), void *userdata);
+
+    /** Enable or disable IO events on this object */
     void (*io_enable)(struct pa_io_event* e, enum pa_io_event_flags events);
+
+    /** Free a IO event source object */
     void (*io_free)(struct pa_io_event* e);
+
+    /** Set a function that is called when the IO event source is destroyed. Use this to free the userdata argument if required */
     void (*io_set_destroy)(struct pa_io_event *e, void (*callback) (struct pa_mainloop_api*a, struct pa_io_event *e, void *userdata));
 
-    /* Time sources */
+    /** Create a new timer event source object for the specified Unix time */
     struct pa_time_event* (*time_new)(struct pa_mainloop_api*a, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*a, struct pa_time_event* e, const struct timeval *tv, void *userdata), void *userdata);
+
+    /** Restart a running or expired timer event source with a new Unix time */
     void (*time_restart)(struct pa_time_event* e, const struct timeval *tv);
+
+    /** Free a deferred timer event source object */
     void (*time_free)(struct pa_time_event* e);
+
+    /** Set a function that is called when the timer event source is destroyed. Use this to free the userdata argument if required */
     void (*time_set_destroy)(struct pa_time_event *e, void (*callback) (struct pa_mainloop_api*a, struct pa_time_event *e, void *userdata));
 
     /** Create a new deferred event source object */
index dacbc153438c434418e6c4e7f30a22f48c9aeec6..4dd6c552455eb427d3cc5788fa6be3e38134f591 100644 (file)
@@ -23,6 +23,9 @@
 ***/
 
 #include "mainloop-api.h"
+#include "cdecl.h"
+
+PA_C_DECL_BEGIN
 
 int pa_signal_init(struct pa_mainloop_api *api);
 void pa_signal_done(void);
@@ -34,4 +37,6 @@ void pa_signal_free(struct pa_signal_event *e);
 
 void pa_signal_set_destroy(struct pa_signal_event *e, void (*callback) (struct pa_mainloop_api *api, struct pa_signal_event*e, void *userdata));
 
+PA_C_DECL_END
+
 #endif
index 3ce18c3159486ec1aa239b826cb433fac9779377..3b1a0270683b1522dc25eec714aa450aeec98230 100644 (file)
@@ -145,7 +145,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) {
         goto finish;
 
     if (!(m->userdata = protocol_new(c, s, m, ma))) {
-        pa_socket_server_free(s);
+        pa_socket_server_unref(s);
         goto finish;
     }
 
index 5449e944dee65b0e3be912450d63f2f8c0c6609b..2414e36beb1b9106ddef299969e5b016f6825b12 100644 (file)
@@ -154,6 +154,7 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) {
     }
 
     pa_xfree(u->scache_item);
+    pa_xfree(u->sink_name);
     
     if (u->display)
         XCloseDisplay(u->display);
index fa3213d0152c01907168357885841f3f9260c085..0fc4416589f63062ec0ec0b0515fc45d3ed0b4af 100644 (file)
   USA.
 ***/
 
+#include "cdecl.h"
+
+PA_C_DECL_BEGIN
+
 enum {
     PA_COMMAND_ERROR,
     PA_COMMAND_TIMEOUT, /* pseudo command */
@@ -121,4 +125,6 @@ enum pa_subscription_event_type {
 
 #define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK))))
 
+PA_C_DECL_END
+
 #endif
index 2d4c4d641ae991b9ed7768e02e5a22db6d222ba1..9ed91fc594a4152b2fe2028196338daf808cc402 100644 (file)
@@ -30,6 +30,7 @@
 #include "pdispatch.h"
 #include "native-common.h"
 #include "xmalloc.h"
+#include "llist.h"
 
 /*#define DEBUG_OPCODES*/
 
@@ -65,37 +66,30 @@ static const char *command_names[PA_COMMAND_MAX] = {
 
 struct reply_info {
     struct pa_pdispatch *pdispatch;
-    struct reply_info *next, *previous;
+    PA_LLIST_FIELDS(struct reply_info);
     void (*callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
     void *userdata;
     uint32_t tag;
     struct pa_time_event *time_event;
-    int callback_is_running;
 };
 
 struct pa_pdispatch {
+    int ref;
     struct pa_mainloop_api *mainloop;
     const struct pa_pdispatch_command *command_table;
     unsigned n_commands;
-    struct reply_info *replies;
+    PA_LLIST_HEAD(struct reply_info, replies);
     void (*drain_callback)(struct pa_pdispatch *pd, void *userdata);
     void *drain_userdata;
-    int in_use, shall_free;
 };
 
 static void reply_info_free(struct reply_info *r) {
     assert(r && r->pdispatch && r->pdispatch->mainloop);
 
-    if (r->pdispatch)
+    if (r->time_event)
         r->pdispatch->mainloop->time_free(r->time_event);
-
-    if (r->previous)
-        r->previous->next = r->next;
-    else
-        r->pdispatch->replies = r->next;
-
-    if (r->next)
-        r->next->previous = r->previous;
+    
+    PA_LLIST_REMOVE(struct reply_info, r->pdispatch->replies, r);
     
     pa_xfree(r);
 }
@@ -107,37 +101,56 @@ struct pa_pdispatch* pa_pdispatch_new(struct pa_mainloop_api *mainloop, const st
     assert((entries && table) || (!entries && !table));
     
     pd = pa_xmalloc(sizeof(struct pa_pdispatch));
+    pd->ref = 1;
     pd->mainloop = mainloop;
     pd->command_table = table;
     pd->n_commands = entries;
-    pd->replies = NULL;
+    PA_LLIST_HEAD_INIT(struct pa_reply_info, pd->replies);
     pd->drain_callback = NULL;
     pd->drain_userdata = NULL;
 
-    pd->in_use = pd->shall_free = 0;
-
     return pd;
 }
 
-void pa_pdispatch_free(struct pa_pdispatch *pd) {
+void pdispatch_free(struct pa_pdispatch *pd) {
     assert(pd);
 
-    if (pd->in_use) {
-        pd->shall_free = 1;
-        return;
-    }
-    
     while (pd->replies)
         reply_info_free(pd->replies);
+    
     pa_xfree(pd);
 }
 
+static void run_action(struct pa_pdispatch *pd, struct reply_info *r, uint32_t command, struct pa_tagstruct *ts) {
+    void (*callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
+    void *userdata;
+    uint32_t tag;
+    assert(r);
+
+    pa_pdispatch_ref(pd);
+    
+    callback = r->callback;
+    userdata = r->userdata;
+    tag = r->tag;
+    
+    reply_info_free(r);
+    
+    callback(pd, command, tag, ts, userdata);
+
+    if (pd->drain_callback && !pa_pdispatch_is_pending(pd))
+        pd->drain_callback(pd, pd->drain_userdata);
+
+    pa_pdispatch_unref(pd);
+}
+
 int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *userdata) {
     uint32_t tag, command;
     struct pa_tagstruct *ts = NULL;
     int ret = -1;
-    assert(pd && packet && packet->data && !pd->in_use);
+    assert(pd && packet && packet->data);
 
+    pa_pdispatch_ref(pd);
+    
     if (packet->length <= 8)
         goto finish;
 
@@ -159,20 +172,8 @@ int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *use
             if (r->tag == tag)
                 break;
 
-        if (r) {
-            pd->in_use = r->callback_is_running = 1;
-            assert(r->callback);
-            r->callback(r->pdispatch, command, tag, ts, r->userdata);
-            pd->in_use = r->callback_is_running = 0;
-            reply_info_free(r);
-            
-            if (pd->shall_free)
-                pa_pdispatch_free(pd);
-            else {
-                if (pd->drain_callback && !pa_pdispatch_is_pending(pd))
-                    pd->drain_callback(pd, pd->drain_userdata);
-            }
-        }
+        if (r)
+            run_action(pd, r, command, ts);
 
     } else if (pd->command_table && command < pd->n_commands) {
         const struct pa_pdispatch_command *c = pd->command_table+command;
@@ -186,33 +187,30 @@ int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *use
         
 finish:
     if (ts)
-        pa_tagstruct_free(ts);    
+        pa_tagstruct_free(ts);
+
+    pa_pdispatch_unref(pd);
 
     return ret;
 }
 
 static void timeout_callback(struct pa_mainloop_api*m, struct pa_time_event*e, const struct timeval *tv, void *userdata) {
     struct reply_info*r = userdata;
-    assert (r && r->time_event == e && r->pdispatch && r->pdispatch->mainloop == m && r->callback);
+    assert(r && r->time_event == e && r->pdispatch && r->pdispatch->mainloop == m && r->callback);
 
-    r->callback(r->pdispatch, PA_COMMAND_TIMEOUT, r->tag, NULL, r->userdata);
-    reply_info_free(r);
-
-    if (r->pdispatch->drain_callback && !pa_pdispatch_is_pending(r->pdispatch))
-        r->pdispatch->drain_callback(r->pdispatch, r->pdispatch->drain_userdata);
+    run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL);
 }
 
 void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int timeout, void (*cb)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void *userdata) {
     struct reply_info *r;
     struct timeval tv;
-    assert(pd && cb);
+    assert(pd && pd->ref >= 1 && cb);
 
     r = pa_xmalloc(sizeof(struct reply_info));
     r->pdispatch = pd;
     r->callback = cb;
     r->userdata = userdata;
     r->tag = tag;
-    r->callback_is_running = 0;
     
     gettimeofday(&tv, NULL);
     tv.tv_sec += timeout;
@@ -220,11 +218,7 @@ void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int time
     r->time_event = pd->mainloop->time_new(pd->mainloop, &tv, timeout_callback, r);
     assert(r->time_event);
 
-    r->previous = NULL;
-    r->next = pd->replies;
-    if (r->next)
-        r->next->previous = r;
-    pd->replies = r;
+    PA_LLIST_PREPEND(struct reply_info, pd->replies, r);
 }
 
 int pa_pdispatch_is_pending(struct pa_pdispatch *pd) {
@@ -248,7 +242,20 @@ void pa_pdispatch_unregister_reply(struct pa_pdispatch *pd, void *userdata) {
     for (r = pd->replies; r; r = n) {
         n = r->next;
 
-        if (!r->callback_is_running && r->userdata == userdata) /* when this item's callback is currently running it is destroyed anyway in the very near future */
+        if (r->userdata == userdata) 
             reply_info_free(r);
     }
 }
+
+void pa_pdispatch_unref(struct pa_pdispatch *pd) {
+    assert(pd && pd->ref >= 1);
+
+    if (!(--(pd->ref)))
+        pdispatch_free(pd);
+}
+
+struct pa_pdispatch* pa_pdispatch_ref(struct pa_pdispatch *pd) {
+    assert(pd && pd->ref >= 1);
+    pd->ref++;
+    return pd;
+}
index 796c1e0317ba175633e873e4ae0e1574639057b2..ff99b18448a785a776c8d096093eac3b48667eb7 100644 (file)
 
 struct pa_pdispatch;
 
-/* It is safe to destroy the calling pdispatch object from all callbacks */
-
 struct pa_pdispatch_command {
     void (*proc)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
 };
 
 struct pa_pdispatch* pa_pdispatch_new(struct pa_mainloop_api *m, const struct pa_pdispatch_command*table, unsigned entries);
-void pa_pdispatch_free(struct pa_pdispatch *pd);
+void pa_pdispatch_unref(struct pa_pdispatch *pd);
+struct pa_pdispatch* pa_pdispatch_ref(struct pa_pdispatch *pd);
 
 int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*p, void *userdata);
 
index 5f849e24247fba93bad751de857c9923aaac6ecb..2a0c24a52b90037cbadb1c7475dc852a143609e0 100644 (file)
@@ -92,11 +92,13 @@ static void context_free(struct pa_context *c) {
         pa_stream_set_state(c->streams, PA_STREAM_TERMINATED);
     
     if (c->client)
-        pa_socket_client_free(c->client);
+        pa_socket_client_unref(c->client);
     if (c->pdispatch)
-        pa_pdispatch_free(c->pdispatch);
-    if (c->pstream)
-        pa_pstream_free(c->pstream);
+        pa_pdispatch_unref(c->pdispatch);
+    if (c->pstream) {
+        pa_pstream_close(c->pstream);
+        pa_pstream_unref(c->pstream);
+    }
     
     if (c->record_streams)
         pa_dynarray_free(c->record_streams, NULL, NULL);
@@ -140,15 +142,17 @@ void pa_context_set_state(struct pa_context *c, enum pa_context_state st) {
         }
 
         if (c->pdispatch)
-            pa_pdispatch_free(c->pdispatch);
+            pa_pdispatch_unref(c->pdispatch);
         c->pdispatch = NULL;
     
-        if (c->pstream)
-            pa_pstream_free(c->pstream);
+        if (c->pstream) {
+            pa_pstream_close(c->pstream);
+            pa_pstream_unref(c->pstream);
+        }
         c->pstream = NULL;
     
         if (c->client)
-            pa_socket_client_free(c->client);
+            pa_socket_client_unref(c->client);
         c->client = NULL;
     }
 
@@ -267,7 +271,7 @@ static void on_connection(struct pa_socket_client *client, struct pa_iochannel*i
 
     pa_context_ref(c);
     
-    pa_socket_client_free(client);
+    pa_socket_client_unref(client);
     c->client = NULL;
 
     if (!io) {
index d7519af4af66fb7aee3ab54ced1e9a718c09328b..437d618e1366e4b64f4456c7b089a8d2e36b913b 100644 (file)
 #include <inttypes.h>
 #include "cdecl.h"
 
-PA_C_DECL_BEGIN;
+PA_C_DECL_BEGIN
 
 /** Return a human readable error message for the specified numeric error code */
 const char* pa_strerror(uint32_t error);
 
-PA_C_DECL_END;
+PA_C_DECL_END
 
 #endif
index a14d0b064a0574d333cfcf6e4c0a2a2e06d56596..9536bbc65c1f7f77039c5add4ca5e67bb849ce6c 100644 (file)
@@ -24,6 +24,7 @@
 #endif
 
 #include <assert.h>
+#include <stdio.h>
 
 #include "polyplib-subscribe.h"
 #include "polyplib-internal.h"
@@ -65,10 +66,15 @@ struct pa_operation* pa_context_subscribe(struct pa_context *c, enum pa_subscrip
     t = pa_tagstruct_new(NULL, 0);
     pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE);
     pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, cb ? m : 0);
+    pa_tagstruct_putu32(t, m);
     pa_pstream_send_tagstruct(c->pstream, t);
     pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o);
 
     return pa_operation_ref(o);
 }
 
+void pa_context_set_subscribe_callback(struct pa_context *c, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) {
+    assert(c);
+    c->subscribe_callback = cb;
+    c->subscribe_userdata = userdata;
+}
index 11aeabe0cd95e6306f6701963c041ee3d3cac333..266d496979f19b4a2757d55122a1cc34c41b1dc8 100644 (file)
@@ -80,6 +80,6 @@ void pa_protocol_cli_free(struct pa_protocol_cli *p) {
     assert(p);
 
     pa_idxset_free(p->connections, free_connection, NULL);
-    pa_socket_server_free(p->server);
+    pa_socket_server_unref(p->server);
     pa_xfree(p);
 }
index b11e19923ed6af109408a12c406804525853796e..fb639b7fb586fc1a4f3dc24d71dafc6b70a5bddf 100644 (file)
@@ -1024,6 +1024,6 @@ void pa_protocol_esound_free(struct pa_protocol_esound *p) {
         connection_free(c);
 
     pa_idxset_free(p->connections, NULL, NULL);
-    pa_socket_server_free(p->server);
+    pa_socket_server_unref(p->server);
     pa_xfree(p);
 }
index 247851fc13569e9386a0d38e516cde7065e0ecda..0d265e332f399d6515c95575c2dcb3a15a671d51 100644 (file)
@@ -306,8 +306,9 @@ static void connection_free(struct connection *c) {
             upload_stream_free((struct upload_stream*) o);
     pa_idxset_free(c->output_streams, NULL, NULL);
 
-    pa_pdispatch_free(c->pdispatch);
-    pa_pstream_free(c->pstream);
+    pa_pdispatch_unref(c->pdispatch);
+    pa_pstream_close(c->pstream);
+    pa_pstream_unref(c->pstream);
     pa_client_free(c->client);
 
     if (c->subscription)
@@ -1330,6 +1331,6 @@ void pa_protocol_native_free(struct pa_protocol_native *p) {
     while ((c = pa_idxset_first(p->connections, NULL)))
         connection_free(c);
     pa_idxset_free(p->connections, NULL, NULL);
-    pa_socket_server_free(p->server);
+    pa_socket_server_unref(p->server);
     pa_xfree(p);
 }
index a95b356c14c18c912d9a175bca44f653af5ff5bf..bd0e14889ba2b072ffa076f38774490d75d0f171 100644 (file)
@@ -426,7 +426,7 @@ void pa_protocol_simple_free(struct pa_protocol_simple *p) {
     }
 
     if (p->server)
-        pa_socket_server_free(p->server);
+        pa_socket_server_unref(p->server);
     pa_xfree(p);
 }
 
index 4f071e4ae41dac6b933476f1ecf3ff24a2dc0a42..2d147e03a7279ec24b111f062326216a6dc60a54 100644 (file)
@@ -57,13 +57,13 @@ struct item_info {
 };
 
 struct pa_pstream {
+    int ref;
+    
     struct pa_mainloop_api *mainloop;
     struct pa_defer_event *defer_event;
     struct pa_iochannel *io;
     struct pa_queue *send_queue;
 
-    int in_use, shall_free;
-    
     int dead;
     void (*die_callback) (struct pa_pstream *p, void *userdata);
     void *die_callback_userdata;
@@ -97,40 +97,24 @@ static void do_write(struct pa_pstream *p);
 static void do_read(struct pa_pstream *p);
 
 static void do_something(struct pa_pstream *p) {
-    assert(p && !p->shall_free);
+    assert(p);
     p->mainloop->defer_enable(p->defer_event, 0);
 
-    if (p->dead)
-        return;
-
-    if (pa_iochannel_is_hungup(p->io)) {
+    pa_pstream_ref(p);
+    
+    if (!p->dead && pa_iochannel_is_hungup(p->io)) {
         p->dead = 1;
         if (p->die_callback)
             p->die_callback(p, p->die_callback_userdata);
-
-        return;
     }
 
-    if (pa_iochannel_is_writable(p->io)) {
-        p->in_use = 1;
+    if (!p->dead && pa_iochannel_is_writable(p->io))
         do_write(p);
-        p->in_use = 0;
-
-        if (p->shall_free) {
-            pa_pstream_free(p);
-            return;
-        }
-    }
 
-    if (pa_iochannel_is_readable(p->io)) {
-        p->in_use = 1;
+    if (!p->dead && pa_iochannel_is_readable(p->io))
         do_read(p);
-        p->in_use = 0;
-        if (p->shall_free) {
-            pa_pstream_free(p);
-            return;
-        }
-    }
+
+    pa_pstream_unref(p);
 }
 
 static void io_callback(struct pa_iochannel*io, void *userdata) {
@@ -150,7 +134,7 @@ struct pa_pstream *pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel
     assert(io);
 
     p = pa_xmalloc(sizeof(struct pa_pstream));
-
+    p->ref = 1;
     p->io = io;
     pa_iochannel_set_callback(io, io_callback, p);
 
@@ -181,8 +165,6 @@ struct pa_pstream *pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel
     p->drain_callback = NULL;
     p->drain_userdata = NULL;
 
-    p->in_use = p->shall_free = 0;
-
     return p;
 }
 
@@ -202,16 +184,11 @@ static void item_free(void *item, void *p) {
     pa_xfree(i);
 }
 
-void pa_pstream_free(struct pa_pstream *p) {
+static void pstream_free(struct pa_pstream *p) {
     assert(p);
 
-    if (p->in_use) {
-        /* If this pstream object is used by someone else on the call stack, we have to postpone the freeing */
-        p->dead = p->shall_free = 1;
-        return;
-    }
-
-    pa_iochannel_free(p->io);
+    pa_pstream_close(p);
+    
     pa_queue_free(p->send_queue, item_free, NULL);
 
     if (p->write.current)
@@ -223,7 +200,6 @@ void pa_pstream_free(struct pa_pstream *p) {
     if (p->read.packet)
         pa_packet_unref(p->read.packet);
 
-    p->mainloop->defer_free(p->defer_event);
     pa_xfree(p);
 }
 
@@ -456,3 +432,36 @@ void pa_pstream_set_drain_callback(struct pa_pstream *p, void (*cb)(struct pa_ps
     p->drain_userdata = userdata;
 }
 
+void pa_pstream_unref(struct pa_pstream*p) {
+    assert(p && p->ref >= 1);
+
+    if (!(--(p->ref)))
+        pstream_free(p);
+}
+
+struct pa_pstream* pa_pstream_ref(struct pa_pstream*p) {
+    assert(p && p->ref >= 1);
+    p->ref++;
+    return p;
+}
+
+void pa_pstream_close(struct pa_pstream *p) {
+    assert(p);
+
+    p->dead = 1;
+
+    if (p->io) {
+        pa_iochannel_free(p->io);
+        p->io = NULL;
+    }
+
+    if (p->defer_event) {
+        p->mainloop->defer_free(p->defer_event);
+        p->defer_event = NULL;
+    }
+
+    p->die_callback = NULL;
+    p->drain_callback = NULL;
+    p->recieve_packet_callback = NULL;
+    p->recieve_memblock_callback = NULL;
+}
index 6b91aeb0bacc50e029f3f94510923900813e4bd1..ff70a85594ef3c5c78181c33431b82162526b80f 100644 (file)
 #include "mainloop-api.h"
 #include "memchunk.h"
 
-/* It is safe to destroy the calling pstream object from all callbacks */
-
 struct pa_pstream;
 
 struct pa_pstream* pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel *io);
-void pa_pstream_free(struct pa_pstream*p);
+void pa_pstream_unref(struct pa_pstream*p);
+struct pa_pstream* pa_pstream_ref(struct pa_pstream*p);
 
 void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet);
 void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk);
@@ -48,4 +47,6 @@ void pa_pstream_set_die_callback(struct pa_pstream *p, void (*callback)(struct p
 
 int pa_pstream_is_pending(struct pa_pstream *p);
 
+void pa_pstream_close(struct pa_pstream *p);
+
 #endif
index dffbfe7d9704d83c85dfb9d894ca582ffe48a24b..3852c1adffeb89e969244425553c1591d5928189 100644 (file)
@@ -39,6 +39,7 @@
 #include "xmalloc.h"
 
 struct pa_socket_client {
+    int ref;
     struct pa_mainloop_api *mainloop;
     int fd;
     struct pa_io_event *io_event;
@@ -52,6 +53,7 @@ static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) {
     assert(m);
 
     c = pa_xmalloc(sizeof(struct pa_socket_client));
+    c->ref = 1;
     c->mainloop = m;
     c->fd = -1;
     c->io_event = NULL;
@@ -62,38 +64,40 @@ static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) {
 }
 
 static void do_call(struct pa_socket_client *c) {
-    struct pa_iochannel *io;
+    struct pa_iochannel *io = NULL;
     int error, lerror;
     assert(c && c->callback);
 
+    pa_socket_client_ref(c);
+    
     lerror = sizeof(error);
     if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &error, &lerror) < 0) {
         fprintf(stderr, "getsockopt(): %s\n", strerror(errno));
-        goto failed;
+        goto finish;
     }
 
     if (lerror != sizeof(error)) {
         fprintf(stderr, "getsocktop() returned invalid size.\n");
-        goto failed;
+        goto finish;
     }
 
     if (error != 0) {
         fprintf(stderr, "connect(): %s\n", strerror(error));
-        goto failed;
+        goto finish;
     }
         
     io = pa_iochannel_new(c->mainloop, c->fd, c->fd);
     assert(io);
+    
+finish:
+    if (!io)
+        close(c->fd);
     c->fd = -1;
+    
+    assert(c->callback);
     c->callback(c, io, c->userdata);
-
-    return;
     
-failed:
-    close(c->fd);
-    c->fd = -1;
-    c->callback(c, NULL, c->userdata);
-    return;
+    pa_socket_client_unref(c);
 }
 
 static void connect_fixed_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) {
@@ -159,7 +163,7 @@ struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, ui
     return c;
 
 fail:
-    pa_socket_client_free(c);
+    pa_socket_client_unref(c);
     return NULL;
 }
 
@@ -188,7 +192,7 @@ struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, co
     return c;
 
 fail:
-    pa_socket_client_free(c);
+    pa_socket_client_unref(c);
     return NULL;
 }
 
@@ -214,12 +218,12 @@ struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m
     return c;
 
 fail:
-    pa_socket_client_free(c);
+    pa_socket_client_unref(c);
     return NULL;
     
 }
 
-void pa_socket_client_free(struct pa_socket_client *c) {
+void socket_client_free(struct pa_socket_client *c) {
     assert(c && c->mainloop);
     if (c->io_event)
         c->mainloop->io_free(c->io_event);
@@ -230,6 +234,19 @@ void pa_socket_client_free(struct pa_socket_client *c) {
     pa_xfree(c);
 }
 
+void pa_socket_client_unref(struct pa_socket_client *c) {
+    assert(c && c->ref >= 1);
+
+    if (!(--(c->ref)))
+        socket_client_free(c);
+}
+
+struct pa_socket_client* pa_socket_client_ref(struct pa_socket_client *c) {
+    assert(c && c->ref >= 1);
+    c->ref++;
+    return c;
+}
+
 void pa_socket_client_set_callback(struct pa_socket_client *c, void (*on_connection)(struct pa_socket_client *c, struct pa_iochannel*io, void *userdata), void *userdata) {
     assert(c);
     c->callback = on_connection;
index 7b9e2a7200d20bddeb0c22e810557d6751d71c63..1957355c60f46accc8ee5cfeaebe86b2dde28b53 100644 (file)
@@ -36,7 +36,8 @@ struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, ui
 struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename);
 struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m, const struct sockaddr *sa, size_t salen);
 
-void pa_socket_client_free(struct pa_socket_client *c);
+void pa_socket_client_unref(struct pa_socket_client *c);
+struct pa_socket_client* pa_socket_client_ref(struct pa_socket_client *c);
 
 void pa_socket_client_set_callback(struct pa_socket_client *c, void (*on_connection)(struct pa_socket_client *c, struct pa_iochannel*io, void *userdata), void *userdata);
 
index 6af2c2865688c572ef72bb153cbc5a828f6d4735..f01e417c4cf134182faba86fce5d88de6136c852 100644 (file)
@@ -40,6 +40,7 @@
 #include "xmalloc.h"
 
 struct pa_socket_server {
+    int ref;
     int fd;
     char *filename;
 
@@ -57,14 +58,16 @@ static void callback(struct pa_mainloop_api *mainloop, struct pa_io_event *e, in
     int nfd;
     assert(s && s->mainloop == mainloop && s->io_event == e && e && fd >= 0 && fd == s->fd);
 
+    pa_socket_server_ref(s);
+    
     if ((nfd = accept(fd, NULL, NULL)) < 0) {
         fprintf(stderr, "accept(): %s\n", strerror(errno));
-        return;
+        goto finish;
     }
 
     if (!s->on_connection) {
         close(nfd);
-        return;
+        goto finish;
     }
 
     /* There should be a check for socket type here */
@@ -76,6 +79,9 @@ static void callback(struct pa_mainloop_api *mainloop, struct pa_io_event *e, in
     io = pa_iochannel_new(s->mainloop, nfd, nfd);
     assert(io);
     s->on_connection(s, io, s->userdata);
+
+finish:
+    pa_socket_server_unref(s);
 }
 
 struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd) {
@@ -83,6 +89,7 @@ struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd)
     assert(m && fd >= 0);
     
     s = pa_xmalloc(sizeof(struct pa_socket_server));
+    s->ref = 1;
     s->fd = fd;
     s->filename = NULL;
     s->on_connection = NULL;
@@ -97,6 +104,12 @@ struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd)
     return s;
 }
 
+struct pa_socket_server* pa_socket_server_ref(struct pa_socket_server *s) {
+    assert(s && s->ref >= 1);
+    s->ref++;
+    return s;
+}
+
 struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename) {
     int fd = -1;
     struct sockaddr_un sa;
@@ -184,7 +197,7 @@ fail:
     return NULL;
 }
 
-void pa_socket_server_free(struct pa_socket_server*s) {
+static void socket_server_free(struct pa_socket_server*s) {
     assert(s);
     close(s->fd);
 
@@ -197,8 +210,15 @@ void pa_socket_server_free(struct pa_socket_server*s) {
     pa_xfree(s);
 }
 
+void pa_socket_server_unref(struct pa_socket_server *s) {
+    assert(s && s->ref >= 1);
+
+    if (!(--(s->ref)))
+        socket_server_free(s);
+}
+
 void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata), void *userdata) {
-    assert(s);
+    assert(s && s->ref >= 1);
 
     s->on_connection = on_connection;
     s->userdata = userdata;
index 6661a66ed1869547b09634078bafa4b51c5b87dd..c9d9193d301665965da8c278a203995779f75b6a 100644 (file)
@@ -34,7 +34,8 @@ struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd)
 struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename);
 struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port);
 
-void pa_socket_server_free(struct pa_socket_server*s);
+void pa_socket_server_unref(struct pa_socket_server*s);
+struct pa_socket_server* pa_socket_server_ref(struct pa_socket_server *s);
 
 void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata), void *userdata);