1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2004-2006 Lennart Poettering 5 6 PulseAudio is free software; you can redistribute it and/or modify 7 it under the terms of the GNU Lesser General Public License as published 8 by the Free Software Foundation; either version 2.1 of the License, 9 or (at your option) any later version. 10 11 PulseAudio is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public License 17 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 18***/ 19 20#ifdef HAVE_CONFIG_H 21#include <config.h> 22#endif 23 24#include <pulse/xmalloc.h> 25#include <pulsecore/macro.h> 26#include <pulsecore/flist.h> 27#include <pulse/fork-detect.h> 28 29#include "internal.h" 30#include "operation.h" 31 32PA_STATIC_FLIST_DECLARE(operations, 0, pa_xfree); 33 34pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t cb, void *userdata) { 35 pa_operation *o; 36 pa_assert(c); 37 38 if (!(o = pa_flist_pop(PA_STATIC_FLIST_GET(operations)))) 39 o = pa_xnew(pa_operation, 1); 40 41 pa_zero(*o); 42 43 PA_REFCNT_INIT(o); 44 o->context = c; 45 o->stream = s; 46 47 o->state = PA_OPERATION_RUNNING; 48 o->callback = cb; 49 o->userdata = userdata; 50 51 /* Refcounting is strictly one-way: from the "bigger" to the "smaller" object. */ 52 PA_LLIST_PREPEND(pa_operation, c->operations, o); 53 pa_operation_ref(o); 54 55 return o; 56} 57 58pa_operation *pa_operation_ref(pa_operation *o) { 59 pa_assert(o); 60 pa_assert(PA_REFCNT_VALUE(o) >= 1); 61 62 PA_REFCNT_INC(o); 63 return o; 64} 65 66void pa_operation_unref(pa_operation *o) { 67 pa_assert(o); 68 pa_assert(PA_REFCNT_VALUE(o) >= 1); 69 70 if (PA_REFCNT_DEC(o) <= 0) { 71 pa_assert(!o->context); 72 pa_assert(!o->stream); 73 74 if (pa_flist_push(PA_STATIC_FLIST_GET(operations), o) < 0) 75 pa_xfree(o); 76 } 77} 78 79static void operation_unlink(pa_operation *o) { 80 pa_assert(o); 81 82 if (o->context) { 83 pa_assert(PA_REFCNT_VALUE(o) >= 2); 84 85 PA_LLIST_REMOVE(pa_operation, o->context->operations, o); 86 pa_operation_unref(o); 87 88 o->context = NULL; 89 } 90 91 o->stream = NULL; 92 o->callback = NULL; 93 o->userdata = NULL; 94 o->state_callback = NULL; 95 o->state_userdata = NULL; 96} 97 98static void operation_set_state(pa_operation *o, pa_operation_state_t st) { 99 pa_assert(o); 100 pa_assert(PA_REFCNT_VALUE(o) >= 1); 101 102 if (st == o->state) 103 return; 104 105 if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) 106 return; 107 108 pa_operation_ref(o); 109 110 o->state = st; 111 112 if (o->state_callback) 113 o->state_callback(o, o->state_userdata); 114 115 if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) 116 operation_unlink(o); 117 118 pa_operation_unref(o); 119} 120 121void pa_operation_cancel(pa_operation *o) { 122 pa_assert(o); 123 pa_assert(PA_REFCNT_VALUE(o) >= 1); 124 125 operation_set_state(o, PA_OPERATION_CANCELED); 126} 127 128void pa_operation_done(pa_operation *o) { 129 pa_assert(o); 130 pa_assert(PA_REFCNT_VALUE(o) >= 1); 131 132 operation_set_state(o, PA_OPERATION_DONE); 133} 134 135pa_operation_state_t pa_operation_get_state(const pa_operation *o) { 136 pa_assert(o); 137 pa_assert(PA_REFCNT_VALUE(o) >= 1); 138 139 return o->state; 140} 141 142void pa_operation_set_state_callback(pa_operation *o, pa_operation_notify_cb_t cb, void *userdata) { 143 pa_assert(o); 144 pa_assert(PA_REFCNT_VALUE(o) >= 1); 145 146 if (pa_detect_fork()) 147 return; 148 149 if (o->state == PA_OPERATION_DONE || o->state == PA_OPERATION_CANCELED) 150 return; 151 152 o->state_callback = cb; 153 o->state_userdata = userdata; 154} 155