[BACK]Return to cmd-queue.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Diff for /src/usr.bin/tmux/cmd-queue.c between version 1.42 and 1.43

version 1.42, 2016/10/15 00:01:01 version 1.43, 2016/10/16 17:55:14
Line 25 
Line 25 
   
 #include "tmux.h"  #include "tmux.h"
   
 static enum cmd_retval  cmdq_continue_one(struct cmd_q *);  /* Global command queue. */
 static void             cmdq_flush(struct cmd_q *);  static struct cmd_q_list global_queue = TAILQ_HEAD_INITIALIZER(global_queue);
   
 /* Create new command queue. */  /* Get command queue name. */
   static const char *
   cmdq_name(struct client *c)
   {
           static char     s[32];
   
           if (c == NULL)
                   return ("<global>");
           xsnprintf(s, sizeof s, "<%p>", c);
           return (s);
   }
   
   /* Get command queue from client. */
   static struct cmd_q_list *
   cmdq_get(struct client *c)
   {
           if (c == NULL)
                   return (&global_queue);
           return (&c->queue);
   }
   
   /* Append an item. */
   void
   cmdq_append(struct client *c, struct cmd_q *cmdq)
   {
           struct cmd_q_list       *queue = cmdq_get(c);
           struct cmd_q            *next;
   
           do {
                   next = cmdq->next;
                   cmdq->next = NULL;
   
                   if (c != NULL)
                           c->references++;
                   cmdq->client = c;
   
                   cmdq->queue = queue;
                   TAILQ_INSERT_TAIL(queue, cmdq, entry);
   
                   cmdq = next;
           } while (cmdq != NULL);
   }
   
   /* Insert an item. */
   void
   cmdq_insert_after(struct cmd_q *after, struct cmd_q *cmdq)
   {
           struct client           *c = after->client;
           struct cmd_q_list       *queue = after->queue;
           struct cmd_q            *next;
   
           do {
                   next = cmdq->next;
                   cmdq->next = NULL;
   
                   if (c != NULL)
                           c->references++;
                   cmdq->client = c;
   
                   cmdq->queue = queue;
                   if (after->next != NULL)
                           TAILQ_INSERT_AFTER(queue, after->next, cmdq, entry);
                   else
                           TAILQ_INSERT_AFTER(queue, after, cmdq, entry);
                   after->next = cmdq;
   
                   cmdq = next;
           } while (cmdq != NULL);
   }
   
   /* Remove an item. */
   static void
   cmdq_remove(struct cmd_q *cmdq)
   {
           free((void *)cmdq->hook);
   
           if (cmdq->client != NULL)
                   server_client_unref(cmdq->client);
   
           if (cmdq->type == CMD_Q_COMMAND)
                   cmd_list_free(cmdq->cmdlist);
   
           TAILQ_REMOVE(cmdq->queue, cmdq, entry);
           free(cmdq);
   }
   
   /* Set command group. */
   static u_int
   cmdq_next_group(void)
   {
           static u_int    group;
   
           return (++group);
   }
   
   /* Remove all subsequent items that match this item's group. */
   static void
   cmdq_remove_group(struct cmd_q *cmdq)
   {
           struct cmd_q    *this, *next;
   
           this = TAILQ_NEXT(cmdq, entry);
           while (this != NULL) {
                   next = TAILQ_NEXT(this, entry);
                   if (this->group == cmdq->group)
                           cmdq_remove(this);
                   this = next;
           }
   }
   
   /* Get a command for the command queue. */
 struct cmd_q *  struct cmd_q *
 cmdq_new(struct client *c)  cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
       struct mouse_event *m, int flags)
 {  {
         struct cmd_q    *cmdq;          struct cmd_q    *cmdq, *first = NULL, *last = NULL;
           struct cmd      *cmd;
           u_int            group = cmdq_next_group();
   
         cmdq = xcalloc(1, sizeof *cmdq);          TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
         cmdq->references = 1;                  cmdq = xcalloc(1, sizeof *cmdq);
         cmdq->flags = 0;                  cmdq->type = CMD_Q_COMMAND;
                   cmdq->group = group;
                   cmdq->flags = flags;
   
                   cmdq->cmdlist = cmdlist;
                   cmdq->cmd = cmd;
   
                   if (current != NULL)
                           cmd_find_copy_state(&cmdq->current, current);
                   if (m != NULL)
                           memcpy(&cmdq->mouse, m, sizeof cmdq->mouse);
                   cmdlist->references++;
   
                   if (first == NULL)
                           first = cmdq;
                   if (last != NULL)
                           last->next = cmdq;
                   last = cmdq;
           }
           return (first);
   }
   
   /* Fire command on command queue. */
   static enum cmd_retval
   cmdq_fire_command(struct cmd_q *cmdq)
   {
           struct client           *c = cmdq->client;
           struct cmd              *cmd = cmdq->cmd;
           enum cmd_retval          retval;
           const char              *name;
           struct cmd_find_state   *fsp, fs;
           int                      flags;
   
           flags = !!(cmd->flags & CMD_CONTROL);
           cmdq_guard(cmdq, "begin", flags);
   
           if (cmd_prepare_state(cmd, cmdq) != 0) {
                   retval = CMD_RETURN_ERROR;
                   goto out;
           }
           if (cmdq->client == NULL)
                   cmdq->client = cmd_find_client(cmdq, NULL, CMD_FIND_QUIET);
   
           retval = cmd->entry->exec(cmd, cmdq);
           if (retval == CMD_RETURN_ERROR)
                   goto out;
   
           if (cmd->entry->flags & CMD_AFTERHOOK) {
                   name = cmd->entry->name;
                   if (cmd_find_valid_state(&cmdq->state.tflag))
                           fsp = &cmdq->state.tflag;
                   else {
                           if (cmd_find_current(&fs, cmdq, CMD_FIND_QUIET) != 0)
                                   goto out;
                           fsp = &fs;
                   }
                   hooks_insert(fsp->s->hooks, cmdq, fsp, "after-%s", name);
           }
   
   out:
         cmdq->client = c;          cmdq->client = c;
         cmdq->client_exit = -1;          if (retval == CMD_RETURN_ERROR)
                   cmdq_guard(cmdq, "error", flags);
           else
                   cmdq_guard(cmdq, "end", flags);
           return (retval);
   }
   
         TAILQ_INIT(&cmdq->queue);  /* Get a callback for the command queue. */
         cmdq->item = NULL;  struct cmd_q *
         cmdq->cmd = NULL;  cmdq_get_callback(cmd_q_cb cb, void *data)
   {
           struct cmd_q    *cmdq;
   
         cmd_find_clear_state(&cmdq->current, NULL, 0);          cmdq = xcalloc(1, sizeof *cmdq);
         cmdq->parent = NULL;          cmdq->type = CMD_Q_CALLBACK;
           cmdq->group = 0;
           cmdq->flags = 0;
   
           cmdq->cb = cb;
           cmdq->data = data;
   
         return (cmdq);          return (cmdq);
 }  }
   
 /* Free command queue */  /* Fire callback on callback queue. */
 int  static enum cmd_retval
 cmdq_free(struct cmd_q *cmdq)  cmdq_fire_callback(struct cmd_q *cmdq)
 {  {
         log_debug("cmdq %p free: %u references", cmdq, cmdq->references);          return (cmdq->cb(cmdq, cmdq->data));
   }
   
         if (--cmdq->references != 0) {  /* Process next item on command queue. */
                 if (cmdq->flags & CMD_Q_DEAD)  u_int
                         return (1);  cmdq_next(struct client *c)
   {
           struct cmd_q_list       *queue = cmdq_get(c);
           const char              *name = cmdq_name(c);
           struct cmd_q            *cmdq;
           enum cmd_retval          retval;
           u_int                    items = 0;
           static u_int             number;
   
           if (TAILQ_EMPTY(queue)) {
                   log_debug("%s %s: empty", __func__, name);
                 return (0);                  return (0);
         }          }
           if (TAILQ_FIRST(queue)->flags & CMD_Q_WAITING) {
                   log_debug("%s %s: waiting", __func__, name);
                   return (0);
           }
   
         cmdq_flush(cmdq);          log_debug("%s %s: enter", __func__, name);
         free(cmdq);          for (;;) {
         return (1);                  cmdq = TAILQ_FIRST(queue);
                   if (cmdq == NULL)
                           break;
                   log_debug("%s %s: type %d, flags %x", __func__, name,
                       cmdq->type, cmdq->flags);
   
                   /*
                    * Any item with the waiting flag set waits until an external
                    * event clears the flag (for example, a job - look at
                    * run-shell).
                    */
                   if (cmdq->flags & CMD_Q_WAITING)
                           goto waiting;
   
                   /*
                    * Items are only fired once, once the fired flag is set, a
                    * waiting flag can only be cleared by an external event.
                    */
                   if (~cmdq->flags & CMD_Q_FIRED) {
                           cmdq->time = time(NULL);
                           cmdq->number = ++number;
   
                           switch (cmdq->type)
                           {
                           case CMD_Q_COMMAND:
                                   retval = cmdq_fire_command(cmdq);
   
                                   /*
                                    * If a command returns an error, remove any
                                    * subsequent commands in the same group.
                                    */
                                   if (retval == CMD_RETURN_ERROR)
                                           cmdq_remove_group(cmdq);
                                   break;
                           case CMD_Q_CALLBACK:
                                   retval = cmdq_fire_callback(cmdq);
                                   break;
                           default:
                                   retval = CMD_RETURN_ERROR;
                                   break;
                           }
                           cmdq->flags |= CMD_Q_FIRED;
   
                           if (retval == CMD_RETURN_WAIT) {
                                   cmdq->flags |= CMD_Q_WAITING;
                                   goto waiting;
                           }
                           items++;
                   }
                   cmdq_remove(cmdq);
           }
   
           log_debug("%s %s: exit (empty)", __func__, name);
           return (items);
   
   waiting:
           log_debug("%s %s: exit (wait)", __func__, name);
           return (items);
 }  }
   
   /* Print a guard line. */
   void
   cmdq_guard(struct cmd_q *cmdq, const char *guard, int flags)
   {
           struct client   *c = cmdq->client;
   
           if (c == NULL || !(c->flags & CLIENT_CONTROL))
                   return;
   
           evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard,
               (long)cmdq->time, cmdq->number, flags);
           server_client_push_stdout(c);
   }
   
 /* Show message from command. */  /* Show message from command. */
 void  void
 cmdq_print(struct cmd_q *cmdq, const char *fmt, ...)  cmdq_print(struct cmd_q *cmdq, const char *fmt, ...)
Line 140 
Line 409 
   
         free(msg);          free(msg);
 }  }
   
 /* Print a guard line. */  
 void  
 cmdq_guard(struct cmd_q *cmdq, const char *guard, int flags)  
 {  
         struct client   *c = cmdq->client;  
   
         if (c == NULL || !(c->flags & CLIENT_CONTROL))  
                 return;  
   
         evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard,  
             (long) cmdq->time, cmdq->number, flags);  
         server_client_push_stdout(c);  
 }  
   
 /* Add command list to queue and begin processing if needed. */  
 void  
 cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist, struct mouse_event *m)  
 {  
         cmdq_append(cmdq, cmdlist, m);  
   
         if (cmdq->item == NULL) {  
                 cmdq->cmd = NULL;  
                 cmdq_continue(cmdq);  
         }  
 }  
   
 /* Add command list to queue. */  
 void  
 cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist, struct mouse_event *m)  
 {  
         struct cmd_q_item       *item;  
   
         item = xcalloc(1, sizeof *item);  
         item->cmdlist = cmdlist;  
         TAILQ_INSERT_TAIL(&cmdq->queue, item, qentry);  
         cmdlist->references++;  
   
         if (m != NULL)  
                 memcpy(&item->mouse, m, sizeof item->mouse);  
         else  
                 item->mouse.valid = 0;  
 }  
   
 /* Process one command. */  
 static enum cmd_retval  
 cmdq_continue_one(struct cmd_q *cmdq)  
 {  
         struct cmd_list         *cmdlist = cmdq->item->cmdlist;  
         struct cmd              *cmd = cmdq->cmd;  
         enum cmd_retval          retval;  
         char                    *tmp;  
         int                      flags = !!(cmd->flags & CMD_CONTROL);  
         const char              *name;  
         struct cmd_find_state   *fsp, fs;  
   
         cmdlist->references++;  
   
         tmp = cmd_print(cmd);  
         log_debug("cmdq %p: %s", cmdq, tmp);  
         free(tmp);  
   
         cmdq->time = time(NULL);  
         cmdq->number++;  
   
         cmdq_guard(cmdq, "begin", flags);  
   
         if (cmd_prepare_state(cmd, cmdq, cmdq->parent) != 0)  
                 goto error;  
   
         retval = cmd->entry->exec(cmd, cmdq);  
         if (retval == CMD_RETURN_ERROR)  
                 goto error;  
   
         if (~cmd->entry->flags & CMD_AFTERHOOK)  
                 goto end;  
   
         if (cmd_find_valid_state(&cmdq->state.tflag))  
                 fsp = &cmdq->state.tflag;  
         else {  
                 if (cmd_find_current(&fs, cmdq, CMD_FIND_QUIET) != 0)  
                         goto end;  
                 fsp = &fs;  
         }  
         name = cmd->entry->name;  
         if (hooks_wait(fsp->s->hooks, cmdq, fsp, "after-%s", name) == 0)  
                 retval = CMD_RETURN_WAIT;  
   
 end:  
         cmdq_guard(cmdq, "end", flags);  
         cmd_list_free(cmdlist);  
         return (retval);  
   
 error:  
         cmdq_guard(cmdq, "error", flags);  
         cmd_list_free(cmdlist);  
         return (CMD_RETURN_ERROR);  
 }  
   
 /* Continue processing command queue. Returns 1 if finishes empty. */  
 int  
 cmdq_continue(struct cmd_q *cmdq)  
 {  
         struct client           *c = cmdq->client;  
         struct cmd_q_item       *next;  
         enum cmd_retval          retval;  
         int                      empty;  
   
         log_debug("continuing cmdq %p: flags %#x (%p)", cmdq, cmdq->flags, c);  
         cmdq->references++;  
   
         empty = TAILQ_EMPTY(&cmdq->queue);  
         if (empty)  
                 goto empty;  
   
         if (cmdq->item == NULL) {  
                 cmdq->item = TAILQ_FIRST(&cmdq->queue);  
                 cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);  
         } else  
                 cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);  
   
         do {  
                 while (cmdq->cmd != NULL) {  
                         retval = cmdq_continue_one(cmdq);  
                         if (retval == CMD_RETURN_ERROR)  
                                 break;  
                         if (retval == CMD_RETURN_WAIT)  
                                 goto out;  
                         if (retval == CMD_RETURN_STOP) {  
                                 cmdq_flush(cmdq);  
                                 goto empty;  
                         }  
                         cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);  
                 }  
                 next = TAILQ_NEXT(cmdq->item, qentry);  
   
                 TAILQ_REMOVE(&cmdq->queue, cmdq->item, qentry);  
                 cmd_list_free(cmdq->item->cmdlist);  
                 free(cmdq->item);  
   
                 cmdq->item = next;  
                 if (cmdq->item != NULL)  
                         cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);  
         } while (cmdq->item != NULL);  
   
 empty:  
         log_debug("cmdq %p empty", cmdq);  
         if (cmdq->client_exit > 0)  
                 cmdq->client->flags |= CLIENT_EXIT;  
         if (cmdq->emptyfn != NULL)  
                 cmdq->emptyfn(cmdq);  
         empty = 1;  
   
 out:  
         cmdq_free(cmdq);  
         return (empty);  
 }  
   
 /* Flush command queue. */  
 static void  
 cmdq_flush(struct cmd_q *cmdq)  
 {  
         struct cmd_q_item       *item, *item1;  
   
         TAILQ_FOREACH_SAFE(item, &cmdq->queue, qentry, item1) {  
                 TAILQ_REMOVE(&cmdq->queue, item, qentry);  
                 cmd_list_free(item->cmdlist);  
                 free(item);  
         }  
         cmdq->item = NULL;  
 }  
   

Legend:
Removed from v.1.42  
changed lines
  Added in v.1.43