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