mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 01:34:18 +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 {
 | 
					struct wait_channel {
 | 
				
			||||||
	const char	       *name;
 | 
						const char	       *name;
 | 
				
			||||||
	int			locked;
 | 
						int			locked;
 | 
				
			||||||
 | 
						int			woken;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	TAILQ_HEAD(, cmd_q)	waiters;
 | 
						TAILQ_HEAD(, cmd_q)	waiters;
 | 
				
			||||||
	TAILQ_HEAD(, cmd_q)	lockers;
 | 
						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 *,
 | 
					enum cmd_retval	cmd_wait_for_unlock(struct cmd_q *, const char *,
 | 
				
			||||||
		    struct wait_channel *);
 | 
							    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
 | 
					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;
 | 
						struct args     	*args = self->args;
 | 
				
			||||||
	const char		*name = args->argv[0];
 | 
						const char		*name = args->argv[0];
 | 
				
			||||||
@@ -89,15 +131,20 @@ cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum cmd_retval
 | 
					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 wait_channel *wc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct cmd_q	*wq, *wq1;
 | 
						struct cmd_q	*wq, *wq1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (wc == NULL || TAILQ_EMPTY(&wc->waiters)) {
 | 
						if (wc == NULL)
 | 
				
			||||||
		cmdq_error(cmdq, "no waiting clients on %s", name);
 | 
							wc = cmd_wait_for_add(name);
 | 
				
			||||||
		return (CMD_RETURN_ERROR);
 | 
					
 | 
				
			||||||
 | 
						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_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) {
 | 
				
			||||||
		TAILQ_REMOVE(&wc->waiters, wq, waitentry);
 | 
							TAILQ_REMOVE(&wc->waiters, wq, waitentry);
 | 
				
			||||||
@@ -105,12 +152,7 @@ cmd_wait_for_signal(struct cmd_q *cmdq, const char *name,
 | 
				
			|||||||
			cmdq_continue(wq);
 | 
								cmdq_continue(wq);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!wc->locked) {
 | 
						cmd_wait_for_remove(wc);
 | 
				
			||||||
		RB_REMOVE(wait_channels, &wait_channels, wc);
 | 
					 | 
				
			||||||
		free((void *)wc->name);
 | 
					 | 
				
			||||||
		free(wc);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return (CMD_RETURN_NORMAL);
 | 
						return (CMD_RETURN_NORMAL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -118,19 +160,23 @@ enum cmd_retval
 | 
				
			|||||||
cmd_wait_for_wait(struct cmd_q *cmdq, const char *name,
 | 
					cmd_wait_for_wait(struct cmd_q *cmdq, const char *name,
 | 
				
			||||||
    struct wait_channel *wc)
 | 
					    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");
 | 
							cmdq_error(cmdq, "not able to wait");
 | 
				
			||||||
		return (CMD_RETURN_ERROR);
 | 
							return (CMD_RETURN_ERROR);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (wc == NULL) {
 | 
						if (wc == NULL)
 | 
				
			||||||
		wc = xmalloc(sizeof *wc);
 | 
							wc = cmd_wait_for_add(name);
 | 
				
			||||||
		wc->name = xstrdup(name);
 | 
					
 | 
				
			||||||
		wc->locked = 0;
 | 
						if (wc->woken) {
 | 
				
			||||||
		TAILQ_INIT(&wc->waiters);
 | 
							log_debug("wait channel %s already woken (client %d)", wc->name,
 | 
				
			||||||
		TAILQ_INIT(&wc->lockers);
 | 
							    c->tty.fd);
 | 
				
			||||||
		RB_INSERT(wait_channels, &wait_channels, wc);
 | 
							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);
 | 
						TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry);
 | 
				
			||||||
	cmdq->references++;
 | 
						cmdq->references++;
 | 
				
			||||||
@@ -147,14 +193,8 @@ cmd_wait_for_lock(struct cmd_q *cmdq, const char *name,
 | 
				
			|||||||
		return (CMD_RETURN_ERROR);
 | 
							return (CMD_RETURN_ERROR);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (wc == NULL) {
 | 
						if (wc == NULL)
 | 
				
			||||||
		wc = xmalloc(sizeof *wc);
 | 
							wc = cmd_wait_for_add(name);
 | 
				
			||||||
		wc->name = xstrdup(name);
 | 
					 | 
				
			||||||
		wc->locked = 0;
 | 
					 | 
				
			||||||
		TAILQ_INIT(&wc->waiters);
 | 
					 | 
				
			||||||
		TAILQ_INIT(&wc->lockers);
 | 
					 | 
				
			||||||
		RB_INSERT(wait_channels, &wait_channels, wc);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (wc->locked) {
 | 
						if (wc->locked) {
 | 
				
			||||||
		TAILQ_INSERT_TAIL(&wc->lockers, cmdq, waitentry);
 | 
							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);
 | 
								cmdq_continue(wq);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		wc->locked = 0;
 | 
							wc->locked = 0;
 | 
				
			||||||
		if (TAILQ_EMPTY(&wc->waiters)) {
 | 
							cmd_wait_for_remove(wc);
 | 
				
			||||||
			RB_REMOVE(wait_channels, &wait_channels, wc);
 | 
					 | 
				
			||||||
			free((void *)wc->name);
 | 
					 | 
				
			||||||
			free(wc);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return (CMD_RETURN_NORMAL);
 | 
						return (CMD_RETURN_NORMAL);
 | 
				
			||||||
@@ -210,8 +246,7 @@ cmd_wait_for_flush(void)
 | 
				
			|||||||
			if (!cmdq_free(wq))
 | 
								if (!cmdq_free(wq))
 | 
				
			||||||
				cmdq_continue(wq);
 | 
									cmdq_continue(wq);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		RB_REMOVE(wait_channels, &wait_channels, wc);
 | 
							wc->locked = 0;
 | 
				
			||||||
		free((void *)wc->name);
 | 
							cmd_wait_for_remove(wc);
 | 
				
			||||||
		free(wc);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user