1*0a6a1f1dSLionel Sambuc /* Id */
2*0a6a1f1dSLionel Sambuc
3*0a6a1f1dSLionel Sambuc /*
4*0a6a1f1dSLionel Sambuc * Copyright (c) 2013 Nicholas Marriott <nicm@users.sourceforge.net>
5*0a6a1f1dSLionel Sambuc * Copyright (c) 2013 Thiago de Arruda <tpadilha84@gmail.com>
6*0a6a1f1dSLionel Sambuc *
7*0a6a1f1dSLionel Sambuc * Permission to use, copy, modify, and distribute this software for any
8*0a6a1f1dSLionel Sambuc * purpose with or without fee is hereby granted, provided that the above
9*0a6a1f1dSLionel Sambuc * copyright notice and this permission notice appear in all copies.
10*0a6a1f1dSLionel Sambuc *
11*0a6a1f1dSLionel Sambuc * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12*0a6a1f1dSLionel Sambuc * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13*0a6a1f1dSLionel Sambuc * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14*0a6a1f1dSLionel Sambuc * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15*0a6a1f1dSLionel Sambuc * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16*0a6a1f1dSLionel Sambuc * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17*0a6a1f1dSLionel Sambuc * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18*0a6a1f1dSLionel Sambuc */
19*0a6a1f1dSLionel Sambuc
20*0a6a1f1dSLionel Sambuc #include <sys/types.h>
21*0a6a1f1dSLionel Sambuc
22*0a6a1f1dSLionel Sambuc #include <stdlib.h>
23*0a6a1f1dSLionel Sambuc #include <string.h>
24*0a6a1f1dSLionel Sambuc
25*0a6a1f1dSLionel Sambuc #include "tmux.h"
26*0a6a1f1dSLionel Sambuc
27*0a6a1f1dSLionel Sambuc /*
28*0a6a1f1dSLionel Sambuc * Block or wake a client on a named wait channel.
29*0a6a1f1dSLionel Sambuc */
30*0a6a1f1dSLionel Sambuc
31*0a6a1f1dSLionel Sambuc enum cmd_retval cmd_wait_for_exec(struct cmd *, struct cmd_q *);
32*0a6a1f1dSLionel Sambuc
33*0a6a1f1dSLionel Sambuc const struct cmd_entry cmd_wait_for_entry = {
34*0a6a1f1dSLionel Sambuc "wait-for", "wait",
35*0a6a1f1dSLionel Sambuc "LSU", 1, 1,
36*0a6a1f1dSLionel Sambuc "[-L|-S|-U] channel",
37*0a6a1f1dSLionel Sambuc 0,
38*0a6a1f1dSLionel Sambuc NULL,
39*0a6a1f1dSLionel Sambuc cmd_wait_for_exec
40*0a6a1f1dSLionel Sambuc };
41*0a6a1f1dSLionel Sambuc
42*0a6a1f1dSLionel Sambuc struct wait_channel {
43*0a6a1f1dSLionel Sambuc const char *name;
44*0a6a1f1dSLionel Sambuc int locked;
45*0a6a1f1dSLionel Sambuc
46*0a6a1f1dSLionel Sambuc TAILQ_HEAD(, cmd_q) waiters;
47*0a6a1f1dSLionel Sambuc TAILQ_HEAD(, cmd_q) lockers;
48*0a6a1f1dSLionel Sambuc
49*0a6a1f1dSLionel Sambuc RB_ENTRY(wait_channel) entry;
50*0a6a1f1dSLionel Sambuc };
51*0a6a1f1dSLionel Sambuc RB_HEAD(wait_channels, wait_channel);
52*0a6a1f1dSLionel Sambuc struct wait_channels wait_channels = RB_INITIALIZER(wait_channels);
53*0a6a1f1dSLionel Sambuc
54*0a6a1f1dSLionel Sambuc int wait_channel_cmp(struct wait_channel *, struct wait_channel *);
55*0a6a1f1dSLionel Sambuc RB_PROTOTYPE(wait_channels, wait_channel, entry, wait_channel_cmp);
56*0a6a1f1dSLionel Sambuc RB_GENERATE(wait_channels, wait_channel, entry, wait_channel_cmp);
57*0a6a1f1dSLionel Sambuc
58*0a6a1f1dSLionel Sambuc int
wait_channel_cmp(struct wait_channel * wc1,struct wait_channel * wc2)59*0a6a1f1dSLionel Sambuc wait_channel_cmp(struct wait_channel *wc1, struct wait_channel *wc2)
60*0a6a1f1dSLionel Sambuc {
61*0a6a1f1dSLionel Sambuc return (strcmp(wc1->name, wc2->name));
62*0a6a1f1dSLionel Sambuc }
63*0a6a1f1dSLionel Sambuc
64*0a6a1f1dSLionel Sambuc enum cmd_retval cmd_wait_for_signal(struct cmd_q *, const char *,
65*0a6a1f1dSLionel Sambuc struct wait_channel *);
66*0a6a1f1dSLionel Sambuc enum cmd_retval cmd_wait_for_wait(struct cmd_q *, const char *,
67*0a6a1f1dSLionel Sambuc struct wait_channel *);
68*0a6a1f1dSLionel Sambuc enum cmd_retval cmd_wait_for_lock(struct cmd_q *, const char *,
69*0a6a1f1dSLionel Sambuc struct wait_channel *);
70*0a6a1f1dSLionel Sambuc enum cmd_retval cmd_wait_for_unlock(struct cmd_q *, const char *,
71*0a6a1f1dSLionel Sambuc struct wait_channel *);
72*0a6a1f1dSLionel Sambuc
73*0a6a1f1dSLionel Sambuc enum cmd_retval
cmd_wait_for_exec(struct cmd * self,struct cmd_q * cmdq)74*0a6a1f1dSLionel Sambuc cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq)
75*0a6a1f1dSLionel Sambuc {
76*0a6a1f1dSLionel Sambuc struct args *args = self->args;
77*0a6a1f1dSLionel Sambuc const char *name = args->argv[0];
78*0a6a1f1dSLionel Sambuc struct wait_channel *wc, wc0;
79*0a6a1f1dSLionel Sambuc
80*0a6a1f1dSLionel Sambuc wc0.name = name;
81*0a6a1f1dSLionel Sambuc wc = RB_FIND(wait_channels, &wait_channels, &wc0);
82*0a6a1f1dSLionel Sambuc
83*0a6a1f1dSLionel Sambuc if (args_has(args, 'S'))
84*0a6a1f1dSLionel Sambuc return (cmd_wait_for_signal(cmdq, name, wc));
85*0a6a1f1dSLionel Sambuc if (args_has(args, 'L'))
86*0a6a1f1dSLionel Sambuc return (cmd_wait_for_lock(cmdq, name, wc));
87*0a6a1f1dSLionel Sambuc if (args_has(args, 'U'))
88*0a6a1f1dSLionel Sambuc return (cmd_wait_for_unlock(cmdq, name, wc));
89*0a6a1f1dSLionel Sambuc return (cmd_wait_for_wait(cmdq, name, wc));
90*0a6a1f1dSLionel Sambuc }
91*0a6a1f1dSLionel Sambuc
92*0a6a1f1dSLionel Sambuc enum cmd_retval
cmd_wait_for_signal(struct cmd_q * cmdq,const char * name,struct wait_channel * wc)93*0a6a1f1dSLionel Sambuc cmd_wait_for_signal(struct cmd_q *cmdq, const char *name,
94*0a6a1f1dSLionel Sambuc struct wait_channel *wc)
95*0a6a1f1dSLionel Sambuc {
96*0a6a1f1dSLionel Sambuc struct cmd_q *wq, *wq1;
97*0a6a1f1dSLionel Sambuc
98*0a6a1f1dSLionel Sambuc if (wc == NULL || TAILQ_EMPTY(&wc->waiters)) {
99*0a6a1f1dSLionel Sambuc cmdq_error(cmdq, "no waiting clients on %s", name);
100*0a6a1f1dSLionel Sambuc return (CMD_RETURN_ERROR);
101*0a6a1f1dSLionel Sambuc }
102*0a6a1f1dSLionel Sambuc
103*0a6a1f1dSLionel Sambuc TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) {
104*0a6a1f1dSLionel Sambuc TAILQ_REMOVE(&wc->waiters, wq, waitentry);
105*0a6a1f1dSLionel Sambuc if (!cmdq_free(wq))
106*0a6a1f1dSLionel Sambuc cmdq_continue(wq);
107*0a6a1f1dSLionel Sambuc }
108*0a6a1f1dSLionel Sambuc
109*0a6a1f1dSLionel Sambuc if (!wc->locked) {
110*0a6a1f1dSLionel Sambuc RB_REMOVE(wait_channels, &wait_channels, wc);
111*0a6a1f1dSLionel Sambuc free(__UNCONST(wc->name));
112*0a6a1f1dSLionel Sambuc free(wc);
113*0a6a1f1dSLionel Sambuc }
114*0a6a1f1dSLionel Sambuc
115*0a6a1f1dSLionel Sambuc return (CMD_RETURN_NORMAL);
116*0a6a1f1dSLionel Sambuc }
117*0a6a1f1dSLionel Sambuc
118*0a6a1f1dSLionel Sambuc enum cmd_retval
cmd_wait_for_wait(struct cmd_q * cmdq,const char * name,struct wait_channel * wc)119*0a6a1f1dSLionel Sambuc cmd_wait_for_wait(struct cmd_q *cmdq, const char *name,
120*0a6a1f1dSLionel Sambuc struct wait_channel *wc)
121*0a6a1f1dSLionel Sambuc {
122*0a6a1f1dSLionel Sambuc if (cmdq->client == NULL || cmdq->client->session != NULL) {
123*0a6a1f1dSLionel Sambuc cmdq_error(cmdq, "not able to wait");
124*0a6a1f1dSLionel Sambuc return (CMD_RETURN_ERROR);
125*0a6a1f1dSLionel Sambuc }
126*0a6a1f1dSLionel Sambuc
127*0a6a1f1dSLionel Sambuc if (wc == NULL) {
128*0a6a1f1dSLionel Sambuc wc = xmalloc(sizeof *wc);
129*0a6a1f1dSLionel Sambuc wc->name = xstrdup(name);
130*0a6a1f1dSLionel Sambuc wc->locked = 0;
131*0a6a1f1dSLionel Sambuc TAILQ_INIT(&wc->waiters);
132*0a6a1f1dSLionel Sambuc TAILQ_INIT(&wc->lockers);
133*0a6a1f1dSLionel Sambuc RB_INSERT(wait_channels, &wait_channels, wc);
134*0a6a1f1dSLionel Sambuc }
135*0a6a1f1dSLionel Sambuc
136*0a6a1f1dSLionel Sambuc TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry);
137*0a6a1f1dSLionel Sambuc cmdq->references++;
138*0a6a1f1dSLionel Sambuc
139*0a6a1f1dSLionel Sambuc return (CMD_RETURN_WAIT);
140*0a6a1f1dSLionel Sambuc }
141*0a6a1f1dSLionel Sambuc
142*0a6a1f1dSLionel Sambuc enum cmd_retval
cmd_wait_for_lock(struct cmd_q * cmdq,const char * name,struct wait_channel * wc)143*0a6a1f1dSLionel Sambuc cmd_wait_for_lock(struct cmd_q *cmdq, const char *name,
144*0a6a1f1dSLionel Sambuc struct wait_channel *wc)
145*0a6a1f1dSLionel Sambuc {
146*0a6a1f1dSLionel Sambuc if (cmdq->client == NULL || cmdq->client->session != NULL) {
147*0a6a1f1dSLionel Sambuc cmdq_error(cmdq, "not able to lock");
148*0a6a1f1dSLionel Sambuc return (CMD_RETURN_ERROR);
149*0a6a1f1dSLionel Sambuc }
150*0a6a1f1dSLionel Sambuc
151*0a6a1f1dSLionel Sambuc if (wc == NULL) {
152*0a6a1f1dSLionel Sambuc wc = xmalloc(sizeof *wc);
153*0a6a1f1dSLionel Sambuc wc->name = xstrdup(name);
154*0a6a1f1dSLionel Sambuc wc->locked = 0;
155*0a6a1f1dSLionel Sambuc TAILQ_INIT(&wc->waiters);
156*0a6a1f1dSLionel Sambuc TAILQ_INIT(&wc->lockers);
157*0a6a1f1dSLionel Sambuc RB_INSERT(wait_channels, &wait_channels, wc);
158*0a6a1f1dSLionel Sambuc }
159*0a6a1f1dSLionel Sambuc
160*0a6a1f1dSLionel Sambuc if (wc->locked) {
161*0a6a1f1dSLionel Sambuc TAILQ_INSERT_TAIL(&wc->lockers, cmdq, waitentry);
162*0a6a1f1dSLionel Sambuc cmdq->references++;
163*0a6a1f1dSLionel Sambuc return (CMD_RETURN_WAIT);
164*0a6a1f1dSLionel Sambuc }
165*0a6a1f1dSLionel Sambuc wc->locked = 1;
166*0a6a1f1dSLionel Sambuc
167*0a6a1f1dSLionel Sambuc return (CMD_RETURN_NORMAL);
168*0a6a1f1dSLionel Sambuc }
169*0a6a1f1dSLionel Sambuc
170*0a6a1f1dSLionel Sambuc enum cmd_retval
cmd_wait_for_unlock(struct cmd_q * cmdq,const char * name,struct wait_channel * wc)171*0a6a1f1dSLionel Sambuc cmd_wait_for_unlock(struct cmd_q *cmdq, const char *name,
172*0a6a1f1dSLionel Sambuc struct wait_channel *wc)
173*0a6a1f1dSLionel Sambuc {
174*0a6a1f1dSLionel Sambuc struct cmd_q *wq;
175*0a6a1f1dSLionel Sambuc
176*0a6a1f1dSLionel Sambuc if (wc == NULL || !wc->locked) {
177*0a6a1f1dSLionel Sambuc cmdq_error(cmdq, "channel %s not locked", name);
178*0a6a1f1dSLionel Sambuc return (CMD_RETURN_ERROR);
179*0a6a1f1dSLionel Sambuc }
180*0a6a1f1dSLionel Sambuc
181*0a6a1f1dSLionel Sambuc if ((wq = TAILQ_FIRST(&wc->lockers)) != NULL) {
182*0a6a1f1dSLionel Sambuc TAILQ_REMOVE(&wc->lockers, wq, waitentry);
183*0a6a1f1dSLionel Sambuc if (!cmdq_free(wq))
184*0a6a1f1dSLionel Sambuc cmdq_continue(wq);
185*0a6a1f1dSLionel Sambuc } else {
186*0a6a1f1dSLionel Sambuc wc->locked = 0;
187*0a6a1f1dSLionel Sambuc if (TAILQ_EMPTY(&wc->waiters)) {
188*0a6a1f1dSLionel Sambuc RB_REMOVE(wait_channels, &wait_channels, wc);
189*0a6a1f1dSLionel Sambuc free(__UNCONST(wc->name));
190*0a6a1f1dSLionel Sambuc free(wc);
191*0a6a1f1dSLionel Sambuc }
192*0a6a1f1dSLionel Sambuc }
193*0a6a1f1dSLionel Sambuc
194*0a6a1f1dSLionel Sambuc return (CMD_RETURN_NORMAL);
195*0a6a1f1dSLionel Sambuc }
196*0a6a1f1dSLionel Sambuc
197