mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 00:56:10 +00:00 
			
		
		
		
	Change wait-for to work when the signal comes before the wait, also use
some helper functions and add some logging.
This commit is contained in:
		
							
								
								
									
										105
									
								
								cmd-wait-for.c
									
									
									
									
									
								
							
							
						
						
									
										105
									
								
								cmd-wait-for.c
									
									
									
									
									
								
							@@ -41,6 +41,7 @@ const struct cmd_entry cmd_wait_for_entry = {
 | 
			
		||||
struct wait_channel {
 | 
			
		||||
	const char	       *name;
 | 
			
		||||
	int			locked;
 | 
			
		||||
	int			woken;
 | 
			
		||||
 | 
			
		||||
	TAILQ_HEAD(, cmd_q)	waiters;
 | 
			
		||||
	TAILQ_HEAD(, cmd_q)	lockers;
 | 
			
		||||
@@ -69,8 +70,49 @@ enum cmd_retval	cmd_wait_for_lock(struct cmd_q *, const char *,
 | 
			
		||||
enum cmd_retval	cmd_wait_for_unlock(struct cmd_q *, const char *,
 | 
			
		||||
		    struct wait_channel *);
 | 
			
		||||
 | 
			
		||||
struct wait_channel	*cmd_wait_for_add(const char *);
 | 
			
		||||
void			 cmd_wait_for_remove(struct wait_channel *wc);
 | 
			
		||||
 | 
			
		||||
struct wait_channel *
 | 
			
		||||
cmd_wait_for_add(const char *name)
 | 
			
		||||
{
 | 
			
		||||
	struct wait_channel *wc;
 | 
			
		||||
 | 
			
		||||
	wc = xmalloc(sizeof *wc);
 | 
			
		||||
	wc->name = xstrdup(name);
 | 
			
		||||
 | 
			
		||||
	wc->locked = 0;
 | 
			
		||||
	wc->woken = 0;
 | 
			
		||||
 | 
			
		||||
	TAILQ_INIT(&wc->waiters);
 | 
			
		||||
	TAILQ_INIT(&wc->lockers);
 | 
			
		||||
 | 
			
		||||
	RB_INSERT(wait_channels, &wait_channels, wc);
 | 
			
		||||
 | 
			
		||||
	log_debug("add wait channel %s", wc->name);
 | 
			
		||||
 | 
			
		||||
	return (wc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
cmd_wait_for_remove(struct wait_channel *wc)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	if (wc->locked)
 | 
			
		||||
		return;
 | 
			
		||||
	if (!TAILQ_EMPTY(&wc->waiters) || !wc->woken)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	log_debug("remove wait channel %s", wc->name);
 | 
			
		||||
 | 
			
		||||
	RB_REMOVE(wait_channels, &wait_channels, wc);
 | 
			
		||||
 | 
			
		||||
	free((void *)wc->name);
 | 
			
		||||
	free(wc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum cmd_retval
 | 
			
		||||
cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq)
 | 
			
		||||
cmd_wait_for_exec(struct cmd *self, unused struct cmd_q *cmdq)
 | 
			
		||||
{
 | 
			
		||||
	struct args     	*args = self->args;
 | 
			
		||||
	const char		*name = args->argv[0];
 | 
			
		||||
@@ -89,15 +131,20 @@ cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum cmd_retval
 | 
			
		||||
cmd_wait_for_signal(struct cmd_q *cmdq, const char *name,
 | 
			
		||||
cmd_wait_for_signal(unused struct cmd_q *cmdq, const char *name,
 | 
			
		||||
    struct wait_channel *wc)
 | 
			
		||||
{
 | 
			
		||||
	struct cmd_q	*wq, *wq1;
 | 
			
		||||
 | 
			
		||||
	if (wc == NULL || TAILQ_EMPTY(&wc->waiters)) {
 | 
			
		||||
		cmdq_error(cmdq, "no waiting clients on %s", name);
 | 
			
		||||
		return (CMD_RETURN_ERROR);
 | 
			
		||||
	if (wc == NULL)
 | 
			
		||||
		wc = cmd_wait_for_add(name);
 | 
			
		||||
 | 
			
		||||
	if (TAILQ_EMPTY(&wc->waiters) && !wc->woken) {
 | 
			
		||||
		log_debug("signal wait channel %s, no waiters", wc->name);
 | 
			
		||||
		wc->woken = 1;
 | 
			
		||||
		return (CMD_RETURN_NORMAL);
 | 
			
		||||
	}
 | 
			
		||||
	log_debug("signal wait channel %s, with waiters", wc->name);
 | 
			
		||||
 | 
			
		||||
	TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) {
 | 
			
		||||
		TAILQ_REMOVE(&wc->waiters, wq, waitentry);
 | 
			
		||||
@@ -105,12 +152,7 @@ cmd_wait_for_signal(struct cmd_q *cmdq, const char *name,
 | 
			
		||||
			cmdq_continue(wq);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!wc->locked) {
 | 
			
		||||
		RB_REMOVE(wait_channels, &wait_channels, wc);
 | 
			
		||||
		free((void *)wc->name);
 | 
			
		||||
		free(wc);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd_wait_for_remove(wc);
 | 
			
		||||
	return (CMD_RETURN_NORMAL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -118,19 +160,23 @@ enum cmd_retval
 | 
			
		||||
cmd_wait_for_wait(struct cmd_q *cmdq, const char *name,
 | 
			
		||||
    struct wait_channel *wc)
 | 
			
		||||
{
 | 
			
		||||
	if (cmdq->client == NULL || cmdq->client->session != NULL) {
 | 
			
		||||
	struct client	*c = cmdq->client;
 | 
			
		||||
 | 
			
		||||
	if (c == NULL || c->session != NULL) {
 | 
			
		||||
		cmdq_error(cmdq, "not able to wait");
 | 
			
		||||
		return (CMD_RETURN_ERROR);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (wc == NULL) {
 | 
			
		||||
		wc = xmalloc(sizeof *wc);
 | 
			
		||||
		wc->name = xstrdup(name);
 | 
			
		||||
		wc->locked = 0;
 | 
			
		||||
		TAILQ_INIT(&wc->waiters);
 | 
			
		||||
		TAILQ_INIT(&wc->lockers);
 | 
			
		||||
		RB_INSERT(wait_channels, &wait_channels, wc);
 | 
			
		||||
	if (wc == NULL)
 | 
			
		||||
		wc = cmd_wait_for_add(name);
 | 
			
		||||
 | 
			
		||||
	if (wc->woken) {
 | 
			
		||||
		log_debug("wait channel %s already woken (client %d)", wc->name,
 | 
			
		||||
		    c->tty.fd);
 | 
			
		||||
		cmd_wait_for_remove(wc);
 | 
			
		||||
		return (CMD_RETURN_NORMAL);
 | 
			
		||||
	}
 | 
			
		||||
	log_debug("wait channel %s not woken (client %d)", wc->name, c->tty.fd);
 | 
			
		||||
 | 
			
		||||
	TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry);
 | 
			
		||||
	cmdq->references++;
 | 
			
		||||
@@ -147,14 +193,8 @@ cmd_wait_for_lock(struct cmd_q *cmdq, const char *name,
 | 
			
		||||
		return (CMD_RETURN_ERROR);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (wc == NULL) {
 | 
			
		||||
		wc = xmalloc(sizeof *wc);
 | 
			
		||||
		wc->name = xstrdup(name);
 | 
			
		||||
		wc->locked = 0;
 | 
			
		||||
		TAILQ_INIT(&wc->waiters);
 | 
			
		||||
		TAILQ_INIT(&wc->lockers);
 | 
			
		||||
		RB_INSERT(wait_channels, &wait_channels, wc);
 | 
			
		||||
	}
 | 
			
		||||
	if (wc == NULL)
 | 
			
		||||
		wc = cmd_wait_for_add(name);
 | 
			
		||||
 | 
			
		||||
	if (wc->locked) {
 | 
			
		||||
		TAILQ_INSERT_TAIL(&wc->lockers, cmdq, waitentry);
 | 
			
		||||
@@ -183,11 +223,7 @@ cmd_wait_for_unlock(struct cmd_q *cmdq, const char *name,
 | 
			
		||||
			cmdq_continue(wq);
 | 
			
		||||
	} else {
 | 
			
		||||
		wc->locked = 0;
 | 
			
		||||
		if (TAILQ_EMPTY(&wc->waiters)) {
 | 
			
		||||
			RB_REMOVE(wait_channels, &wait_channels, wc);
 | 
			
		||||
			free((void *)wc->name);
 | 
			
		||||
			free(wc);
 | 
			
		||||
		}
 | 
			
		||||
		cmd_wait_for_remove(wc);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (CMD_RETURN_NORMAL);
 | 
			
		||||
@@ -210,8 +246,7 @@ cmd_wait_for_flush(void)
 | 
			
		||||
			if (!cmdq_free(wq))
 | 
			
		||||
				cmdq_continue(wq);
 | 
			
		||||
		}
 | 
			
		||||
		RB_REMOVE(wait_channels, &wait_channels, wc);
 | 
			
		||||
		free((void *)wc->name);
 | 
			
		||||
		free(wc);
 | 
			
		||||
		wc->locked = 0;
 | 
			
		||||
		cmd_wait_for_remove(wc);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user