1 /* PipeWire
2 *
3 * Copyright © 2018 Wim Taymans
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 #include "pipewire/log.h"
26 #include "pipewire/main-loop.h"
27 #include "pipewire/private.h"
28
29 PW_LOG_TOPIC_EXTERN(log_main_loop);
30 #define PW_LOG_TOPIC_DEFAULT log_main_loop
31
do_stop(void * data,uint64_t count)32 static void do_stop(void *data, uint64_t count)
33 {
34 struct pw_main_loop *this = data;
35 pw_log_debug("%p: do stop", this);
36 this->running = false;
37 }
38
loop_new(struct pw_loop * loop,const struct spa_dict * props)39 static struct pw_main_loop *loop_new(struct pw_loop *loop, const struct spa_dict *props)
40 {
41 struct pw_main_loop *this;
42 int res;
43
44 this = calloc(1, sizeof(struct pw_main_loop));
45 if (this == NULL) {
46 res = -errno;
47 goto error_cleanup;
48 }
49
50 pw_log_debug("%p: new", this);
51
52 if (loop == NULL) {
53 loop = pw_loop_new(props);
54 this->created = true;
55 }
56 if (loop == NULL) {
57 res = -errno;
58 goto error_free;
59 }
60 this->loop = loop;
61
62 this->event = pw_loop_add_event(this->loop, do_stop, this);
63 if (this->event == NULL) {
64 res = -errno;
65 goto error_free_loop;
66 }
67
68 spa_hook_list_init(&this->listener_list);
69
70 return this;
71
72 error_free_loop:
73 if (this->created && this->loop)
74 pw_loop_destroy(this->loop);
75 error_free:
76 free(this);
77 error_cleanup:
78 errno = -res;
79 return NULL;
80 }
81
82 /** Create a new main loop
83 * \return a newly allocated \ref pw_main_loop
84 *
85 */
86 SPA_EXPORT
pw_main_loop_new(const struct spa_dict * props)87 struct pw_main_loop *pw_main_loop_new(const struct spa_dict *props)
88 {
89 return loop_new(NULL, props);
90 }
91
92 /** Destroy a main loop
93 * \param loop the main loop to destroy
94 *
95 */
96 SPA_EXPORT
pw_main_loop_destroy(struct pw_main_loop * loop)97 void pw_main_loop_destroy(struct pw_main_loop *loop)
98 {
99 pw_log_debug("%p: destroy", loop);
100 pw_main_loop_emit_destroy(loop);
101
102 if (loop->created)
103 pw_loop_destroy(loop->loop);
104
105 spa_hook_list_clean(&loop->listener_list);
106
107 free(loop);
108 }
109
110 SPA_EXPORT
pw_main_loop_add_listener(struct pw_main_loop * loop,struct spa_hook * listener,const struct pw_main_loop_events * events,void * data)111 void pw_main_loop_add_listener(struct pw_main_loop *loop,
112 struct spa_hook *listener,
113 const struct pw_main_loop_events *events,
114 void *data)
115 {
116 spa_hook_list_append(&loop->listener_list, listener, events, data);
117 }
118
119 SPA_EXPORT
pw_main_loop_get_loop(struct pw_main_loop * loop)120 struct pw_loop * pw_main_loop_get_loop(struct pw_main_loop *loop)
121 {
122 return loop->loop;
123 }
124
125 /** Stop a main loop
126 * \param loop a \ref pw_main_loop to stop
127 *
128 * The call to \ref pw_main_loop_run() will return
129 *
130 */
131 SPA_EXPORT
pw_main_loop_quit(struct pw_main_loop * loop)132 int pw_main_loop_quit(struct pw_main_loop *loop)
133 {
134 pw_log_debug("%p: quit", loop);
135 return pw_loop_signal_event(loop->loop, loop->event);
136 }
137
138 /** Start a main loop
139 * \param loop the main loop to start
140 *
141 * Start running \a loop. This function blocks until \ref pw_main_loop_quit()
142 * has been called
143 *
144 */
145 SPA_EXPORT
pw_main_loop_run(struct pw_main_loop * loop)146 int pw_main_loop_run(struct pw_main_loop *loop)
147 {
148 int res = 0;
149
150 pw_log_debug("%p: run", loop);
151
152 loop->running = true;
153 pw_loop_enter(loop->loop);
154 while (loop->running) {
155 if ((res = pw_loop_iterate(loop->loop, -1)) < 0) {
156 if (res == -EINTR)
157 continue;
158 pw_log_warn("%p: iterate error %d (%s)",
159 loop, res, spa_strerror(res));
160 }
161 }
162 pw_loop_leave(loop->loop);
163 return res;
164 }
165