diff options
| author | Ingo Molnar <mingo@kernel.org> | 2012-04-14 13:18:27 +0200 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2012-04-14 13:19:04 +0200 |
| commit | 6ac1ef482d7ae0c690f1640bf6eb818ff9a2d91e (patch) | |
| tree | 021cc9f6b477146fcebe6f3be4752abfa2ba18a9 /arch/um/drivers/chan_kern.c | |
| parent | 682968e0c425c60f0dde37977e5beb2b12ddc4cc (diff) | |
| parent | a385ec4f11bdcf81af094c03e2444ee9b7fad2e5 (diff) | |
Merge branch 'perf/core' into perf/uprobes
Merge in latest upstream (and the latest perf development tree),
to prepare for tooling changes, and also to pick up v3.4 MM
changes that the uprobes code needs to take care of.
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/um/drivers/chan_kern.c')
| -rw-r--r-- | arch/um/drivers/chan_kern.c | 198 |
1 files changed, 88 insertions, 110 deletions
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 420e2c800799..ca4c7ebfd0aa 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -140,18 +140,18 @@ static int open_chan(struct list_head *chans) return err; } -void chan_enable_winch(struct list_head *chans, struct tty_struct *tty) +void chan_enable_winch(struct chan *chan, struct tty_struct *tty) { - struct list_head *ele; - struct chan *chan; + if (chan && chan->primary && chan->ops->winch) + register_winch(chan->fd, tty); +} - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - if (chan->primary && chan->output && chan->ops->winch) { - register_winch(chan->fd, tty); - return; - } - } +static void line_timer_cb(struct work_struct *work) +{ + struct line *line = container_of(work, struct line, task.work); + + if (!line->throttled) + chan_interrupt(line, line->tty, line->driver->read_irq); } int enable_chan(struct line *line) @@ -160,6 +160,8 @@ int enable_chan(struct line *line) struct chan *chan; int err; + INIT_DELAYED_WORK(&line->task, line_timer_cb); + list_for_each(ele, &line->chan_list) { chan = list_entry(ele, struct chan, list); err = open_one_chan(chan); @@ -183,7 +185,7 @@ int enable_chan(struct line *line) return 0; out_close: - close_chan(&line->chan_list, 0); + close_chan(line); return err; } @@ -244,7 +246,7 @@ static void close_one_chan(struct chan *chan, int delay_free_irq) chan->fd = -1; } -void close_chan(struct list_head *chans, int delay_free_irq) +void close_chan(struct line *line) { struct chan *chan; @@ -253,77 +255,50 @@ void close_chan(struct list_head *chans, int delay_free_irq) * state. Then, the first one opened will have the original state, * so it must be the last closed. */ - list_for_each_entry_reverse(chan, chans, list) { - close_one_chan(chan, delay_free_irq); + list_for_each_entry_reverse(chan, &line->chan_list, list) { + close_one_chan(chan, 0); } } -void deactivate_chan(struct list_head *chans, int irq) +void deactivate_chan(struct chan *chan, int irq) { - struct list_head *ele; - - struct chan *chan; - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - - if (chan->enabled && chan->input) - deactivate_fd(chan->fd, irq); - } + if (chan && chan->enabled) + deactivate_fd(chan->fd, irq); } -void reactivate_chan(struct list_head *chans, int irq) +void reactivate_chan(struct chan *chan, int irq) { - struct list_head *ele; - struct chan *chan; - - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - - if (chan->enabled && chan->input) - reactivate_fd(chan->fd, irq); - } + if (chan && chan->enabled) + reactivate_fd(chan->fd, irq); } -int write_chan(struct list_head *chans, const char *buf, int len, +int write_chan(struct chan *chan, const char *buf, int len, int write_irq) { - struct list_head *ele; - struct chan *chan = NULL; int n, ret = 0; - if (len == 0) + if (len == 0 || !chan || !chan->ops->write) return 0; - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - if (!chan->output || (chan->ops->write == NULL)) - continue; - - n = chan->ops->write(chan->fd, buf, len, chan->data); - if (chan->primary) { - ret = n; - if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len))) - reactivate_fd(chan->fd, write_irq); - } + n = chan->ops->write(chan->fd, buf, len, chan->data); + if (chan->primary) { + ret = n; + if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len))) + reactivate_fd(chan->fd, write_irq); } return ret; } -int console_write_chan(struct list_head *chans, const char *buf, int len) +int console_write_chan(struct chan *chan, const char *buf, int len) { - struct list_head *ele; - struct chan *chan; int n, ret = 0; - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - if (!chan->output || (chan->ops->console_write == NULL)) - continue; + if (!chan || !chan->ops->console_write) + return 0; - n = chan->ops->console_write(chan->fd, buf, len); - if (chan->primary) - ret = n; - } + n = chan->ops->console_write(chan->fd, buf, len); + if (chan->primary) + ret = n; return ret; } @@ -340,20 +315,24 @@ int console_open_chan(struct line *line, struct console *co) return 0; } -int chan_window_size(struct list_head *chans, unsigned short *rows_out, +int chan_window_size(struct line *line, unsigned short *rows_out, unsigned short *cols_out) { - struct list_head *ele; struct chan *chan; - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - if (chan->primary) { - if (chan->ops->window_size == NULL) - return 0; - return chan->ops->window_size(chan->fd, chan->data, - rows_out, cols_out); - } + chan = line->chan_in; + if (chan && chan->primary) { + if (chan->ops->window_size == NULL) + return 0; + return chan->ops->window_size(chan->fd, chan->data, + rows_out, cols_out); + } + chan = line->chan_out; + if (chan && chan->primary) { + if (chan->ops->window_size == NULL) + return 0; + return chan->ops->window_size(chan->fd, chan->data, + rows_out, cols_out); } return 0; } @@ -429,21 +408,15 @@ static int chan_pair_config_string(struct chan *in, struct chan *out, return n; } -int chan_config_string(struct list_head *chans, char *str, int size, +int chan_config_string(struct line *line, char *str, int size, char **error_out) { - struct list_head *ele; - struct chan *chan, *in = NULL, *out = NULL; + struct chan *in = line->chan_in, *out = line->chan_out; - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - if (!chan->primary) - continue; - if (chan->input) - in = chan; - if (chan->output) - out = chan; - } + if (in && !in->primary) + in = NULL; + if (out && !out->primary) + out = NULL; return chan_pair_config_string(in, out, str, size, error_out); } @@ -547,10 +520,14 @@ int parse_chan_pair(char *str, struct line *line, int device, char *in, *out; if (!list_empty(chans)) { + line->chan_in = line->chan_out = NULL; free_chan(chans); INIT_LIST_HEAD(chans); } + if (!str) + return 0; + out = strchr(str, ','); if (out != NULL) { in = str; @@ -562,6 +539,7 @@ int parse_chan_pair(char *str, struct line *line, int device, new->input = 1; list_add(&new->list, chans); + line->chan_in = new; new = parse_chan(line, out, device, opts, error_out); if (new == NULL) @@ -569,6 +547,7 @@ int parse_chan_pair(char *str, struct line *line, int device, list_add(&new->list, chans); new->output = 1; + line->chan_out = new; } else { new = parse_chan(line, str, device, opts, error_out); @@ -578,43 +557,42 @@ int parse_chan_pair(char *str, struct line *line, int device, list_add(&new->list, chans); new->input = 1; new->output = 1; + line->chan_in = line->chan_out = new; } return 0; } -void chan_interrupt(struct list_head *chans, struct delayed_work *task, - struct tty_struct *tty, int irq) +void chan_interrupt(struct line *line, struct tty_struct *tty, int irq) { - struct list_head *ele, *next; - struct chan *chan; + struct chan *chan = line->chan_in; int err; char c; - list_for_each_safe(ele, next, chans) { - chan = list_entry(ele, struct chan, list); - if (!chan->input || (chan->ops->read == NULL)) - continue; - do { - if (tty && !tty_buffer_request_room(tty, 1)) { - schedule_delayed_work(task, 1); - goto out; - } - err = chan->ops->read(chan->fd, &c, chan->data); - if (err > 0) - tty_receive_char(tty, c); - } while (err > 0); - - if (err == 0) - reactivate_fd(chan->fd, irq); - if (err == -EIO) { - if (chan->primary) { - if (tty != NULL) - tty_hangup(tty); - close_chan(chans, 1); - return; - } - else close_one_chan(chan, 1); + if (!chan || !chan->ops->read) + goto out; + + do { + if (tty && !tty_buffer_request_room(tty, 1)) { + schedule_delayed_work(&line->task, 1); + goto out; } + err = chan->ops->read(chan->fd, &c, chan->data); + if (err > 0) + tty_receive_char(tty, c); + } while (err > 0); + + if (err == 0) + reactivate_fd(chan->fd, irq); + if (err == -EIO) { + if (chan->primary) { + if (tty != NULL) + tty_hangup(tty); + if (line->chan_out != chan) + close_one_chan(line->chan_out, 1); + } + close_one_chan(chan, 1); + if (chan->primary) + return; } out: if (tty) |
