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