From: Andrew Morton Make my mouse go again. Cc: Dmitry Torokhov Signed-off-by: Andrew Morton --- drivers/input/evdev.c | 63 +++++++++++++++-------------- drivers/input/input.c | 59 +++++++-------------------- drivers/input/joydev.c | 52 +++++++++++------------- drivers/input/mousedev.c | 78 ++++++++++++++++++------------------- drivers/input/tsdev.c | 61 ++++++++++++++-------------- include/linux/input.h | 3 - 6 files changed, 143 insertions(+), 173 deletions(-) diff -puN drivers/input/evdev.c~revert-input-make-input_openclose_device-more-robust drivers/input/evdev.c --- a/drivers/input/evdev.c~revert-input-make-input_openclose_device-more-robust +++ a/drivers/input/evdev.c @@ -23,7 +23,8 @@ #include struct evdev { - int dead; + int exist; + int open; int minor; char name[16]; struct input_handle handle; @@ -89,6 +90,9 @@ static int evdev_flush(struct file *file { struct evdev_list *list = file->private_data; + if (!list->evdev->exist) + return -ENODEV; + return input_flush_device(&list->evdev->handle, file); } @@ -115,7 +119,9 @@ static int evdev_release(struct inode *i list_del(&list->node); kfree(list); - input_close_device(&evdev->handle); + if (!--evdev->open && evdev->exist) + input_close_device(&evdev->handle); + kref_put(&evdev->kref, evdev_free); return 0; @@ -125,14 +131,13 @@ static int evdev_open(struct inode *inod { struct evdev_list *list; struct evdev *evdev; - int error; int i = iminor(inode) - EVDEV_MINOR_BASE; if (i >= EVDEV_MINORS) return -ENODEV; evdev = evdev_table[i]; - if (!evdev || evdev->dead) + if (!evdev || !evdev->exist) return -ENODEV; list = kzalloc(sizeof(struct evdev_list), GFP_KERNEL); @@ -145,16 +150,10 @@ static int evdev_open(struct inode *inod list_add_tail(&list->node, &evdev->list); file->private_data = list; - error = input_open_device(&evdev->handle); - if (error) - goto fail; + if (!evdev->open++ && evdev->exist) + input_open_device(&evdev->handle); return 0; - - fail: list_del(&list->node); - kfree(list); - kref_put(&evdev->kref, evdev_free); - return error; } #ifdef CONFIG_COMPAT @@ -255,46 +254,44 @@ static int evdev_event_to_user(char __us #endif /* CONFIG_COMPAT */ -static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) { struct evdev_list *list = file->private_data; - struct evdev *evdev = list->evdev; struct input_event event; int retval = 0; - if (evdev->dead) + if (!list->evdev->exist) return -ENODEV; while (retval < count) { if (evdev_event_from_user(buffer + retval, &event)) return -EFAULT; - input_inject_event(&evdev->handle, event.type, event.code, event.value); + input_inject_event(&list->evdev->handle, event.type, event.code, event.value); retval += evdev_event_size(); } return retval; } -static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) +static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos) { struct evdev_list *list = file->private_data; - struct evdev *evdev = list->evdev; int retval; if (count < evdev_event_size()) return -EINVAL; - if (list->head == list->tail && !evdev->dead && (file->f_flags & O_NONBLOCK)) + if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK)) return -EAGAIN; - retval = wait_event_interruptible(evdev->wait, - list->head != list->tail || evdev->dead); + retval = wait_event_interruptible(list->evdev->wait, + list->head != list->tail || (!list->evdev->exist)); if (retval) return retval; - if (evdev->dead) + if (!list->evdev->exist) return -ENODEV; while (list->head != list->tail && retval + evdev_event_size() <= count) { @@ -315,11 +312,10 @@ static ssize_t evdev_read(struct file *f static unsigned int evdev_poll(struct file *file, poll_table *wait) { struct evdev_list *list = file->private_data; - struct evdev *evdev = list->evdev; - poll_wait(file, &evdev->wait, wait); - return (list->head != list->tail ? POLLIN | POLLRDNORM : 0) | - (evdev->dead ? POLLHUP | POLLERR : 0); + poll_wait(file, &list->evdev->wait, wait); + return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) | + (list->evdev->exist ? 0 : (POLLHUP | POLLERR)); } #ifdef CONFIG_COMPAT @@ -411,7 +407,7 @@ static long evdev_ioctl_handler(struct f int i, t, u, v; int error; - if (evdev->dead) + if (!evdev->exist) return -ENODEV; switch (cmd) { @@ -654,6 +650,7 @@ static int evdev_connect(struct input_ha INIT_LIST_HEAD(&evdev->list); init_waitqueue_head(&evdev->wait); + evdev->exist = 1; evdev->minor = minor; evdev->handle.dev = dev; evdev->handle.name = evdev->name; @@ -701,11 +698,15 @@ static void evdev_disconnect(struct inpu sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name); class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor)); + evdev->exist = 0; - evdev->dead = 1; - wake_up_interruptible(&evdev->wait); - list_for_each_entry(list, &evdev->list, node) - kill_fasync(&list->fasync, SIGIO, POLL_HUP); + if (evdev->open) { + input_flush_device(handle, NULL); + input_close_device(handle); + wake_up_interruptible(&evdev->wait); + list_for_each_entry(list, &evdev->list, node) + kill_fasync(&list->fasync, SIGIO, POLL_HUP); + } kref_put(&evdev->kref, evdev_free); } diff -puN drivers/input/input.c~revert-input-make-input_openclose_device-more-robust drivers/input/input.c --- a/drivers/input/input.c~revert-input-make-input_openclose_device-more-robust +++ a/drivers/input/input.c @@ -261,43 +261,26 @@ int input_open_device(struct input_handl if (err) return err; - if (dev->dead) { - err = -ENODEV; - goto out; - } - handle->open++; - if (!dev->users++ && dev->open) { + if (!dev->users++ && dev->open) err = dev->open(dev); - if (err) { - dev->users--; - handle->open--; - } - } - out: + if (err) + handle->open--; + mutex_unlock(&dev->mutex); + return err; } EXPORT_SYMBOL(input_open_device); -int input_flush_device(struct input_handle *handle, struct file *file) +int input_flush_device(struct input_handle* handle, struct file* file) { - struct input_dev *dev = handle->dev; - int ret; - - mutex_lock(&dev->mutex); + if (handle->dev->flush) + return handle->dev->flush(handle->dev, file); - if (dev->dead) - ret = -ENODEV; - else if (dev->flush) - ret = dev->flush(dev, file); - else - ret = 0; - - mutex_unlock(&dev->mutex); - return ret; + return 0; } EXPORT_SYMBOL(input_flush_device); @@ -309,14 +292,9 @@ void input_close_device(struct input_han mutex_lock(&dev->mutex); - if (handle->open) { - if (dev->users) { - if (dev->close && !dev->dead) - dev->close(dev); - dev->users--; - } - handle->open--; - } + if (!--dev->users && dev->close) + dev->close(dev); + handle->open--; mutex_unlock(&dev->mutex); } @@ -1051,19 +1029,14 @@ void input_unregister_device(struct inpu list_del_init(&dev->node); - mutex_lock(&dev->mutex); - if (dev->flush) - dev->flush(dev, NULL); - if (dev->users && dev->close) - dev->close(dev); - dev->name = dev->phys = dev->uniq = NULL; - dev->dead = 1; - mutex_unlock(&dev->mutex); - sysfs_remove_group(&dev->cdev.kobj, &input_dev_caps_attr_group); sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group); sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group); + mutex_lock(&dev->mutex); + dev->name = dev->phys = dev->uniq = NULL; + mutex_unlock(&dev->mutex); + class_device_unregister(&dev->cdev); input_wakeup_procfs_readers(); diff -puN drivers/input/joydev.c~revert-input-make-input_openclose_device-more-robust drivers/input/joydev.c --- a/drivers/input/joydev.c~revert-input-make-input_openclose_device-more-robust +++ a/drivers/input/joydev.c @@ -37,7 +37,8 @@ MODULE_LICENSE("GPL"); #define JOYDEV_BUFFER_SIZE 64 struct joydev { - int dead; + int exist; + int open; int minor; char name[16]; struct input_handle handle; @@ -158,7 +159,9 @@ static int joydev_release(struct inode * list_del(&list->node); kfree(list); - input_close_device(&joydev->handle); + if (!--joydev->open && joydev->exist) + input_close_device(&list->joydev->handle); + kref_put(&joydev->kref, joydev_free); return 0; @@ -168,14 +171,13 @@ static int joydev_open(struct inode *ino { struct joydev_list *list; struct joydev *joydev; - int error; int i = iminor(inode) - JOYDEV_MINOR_BASE; if (i >= JOYDEV_MINORS) return -ENODEV; joydev = joydev_table[i]; - if (!joydev || joydev->dead) + if (!joydev || !joydev->exist) return -ENODEV; list = kzalloc(sizeof(struct joydev_list), GFP_KERNEL); @@ -188,16 +190,10 @@ static int joydev_open(struct inode *ino list_add_tail(&list->node, &joydev->list); file->private_data = list; - error = input_open_device(&joydev->handle); - if (error) - goto fail; + if (!joydev->open++ && joydev->exist) + input_open_device(&list->joydev->handle); return 0; - - fail: list_del(&list->node); - kfree(list); - kref_put(&joydev->kref, joydev_free); - return error; } static ssize_t joydev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) @@ -212,7 +208,7 @@ static ssize_t joydev_read(struct file * struct input_dev *input = joydev->handle.dev; int retval = 0; - if (joydev->dead) + if (!joydev->exist) return -ENODEV; if (count < sizeof(struct js_event)) @@ -241,15 +237,15 @@ static ssize_t joydev_read(struct file * list->head == list->tail && (file->f_flags & O_NONBLOCK)) return -EAGAIN; - retval = wait_event_interruptible(joydev->wait, - joydev->dead || + retval = wait_event_interruptible(list->joydev->wait, + !list->joydev->exist || list->startup < joydev->nabs + joydev->nkey || list->head != list->tail); if (retval) return retval; - if (joydev->dead) + if (!list->joydev->exist) return -ENODEV; while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) { @@ -291,12 +287,10 @@ static ssize_t joydev_read(struct file * static unsigned int joydev_poll(struct file *file, poll_table *wait) { struct joydev_list *list = file->private_data; - struct joydev *joydev = list->joydev; - poll_wait(file, &joydev->wait, wait); - return (list->head != list->tail || - list->startup < joydev->nabs + joydev->nkey ? POLLIN | POLLRDNORM : 0) | - (joydev->dead ? POLLHUP | POLLERR : 0); + poll_wait(file, &list->joydev->wait, wait); + return ((list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) ? + (POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR)); } static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp) @@ -397,7 +391,7 @@ static long joydev_compat_ioctl(struct f struct JS_DATA_SAVE_TYPE_32 ds32; int err; - if (joydev->dead) + if (!joydev->exist) return -ENODEV; switch(cmd) { @@ -448,7 +442,7 @@ static int joydev_ioctl(struct inode *in struct joydev *joydev = list->joydev; void __user *argp = (void __user *)arg; - if (joydev->dead) + if (!joydev->exist) return -ENODEV; switch(cmd) { @@ -505,6 +499,7 @@ static int joydev_connect(struct input_h init_waitqueue_head(&joydev->wait); joydev->minor = minor; + joydev->exist = 1; joydev->handle.dev = dev; joydev->handle.name = joydev->name; joydev->handle.handler = handler; @@ -591,11 +586,14 @@ static void joydev_disconnect(struct inp sysfs_remove_link(&input_class.subsys.kset.kobj, joydev->name); class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); + joydev->exist = 0; - joydev->dead = 1; - wake_up_interruptible(&joydev->wait); - list_for_each_entry(list, &joydev->list, node) - kill_fasync(&list->fasync, SIGIO, POLL_HUP); + if (joydev->open) { + input_close_device(handle); + wake_up_interruptible(&joydev->wait); + list_for_each_entry(list, &joydev->list, node) + kill_fasync(&list->fasync, SIGIO, POLL_HUP); + } kref_put(&joydev->kref, joydev_free); } diff -puN drivers/input/mousedev.c~revert-input-make-input_openclose_device-more-robust drivers/input/mousedev.c --- a/drivers/input/mousedev.c~revert-input-make-input_openclose_device-more-robust +++ a/drivers/input/mousedev.c @@ -58,7 +58,8 @@ struct mousedev_hw_data { }; struct mousedev { - int dead; + int exist; + int open; int minor; char name[16]; struct input_handle handle; @@ -111,7 +112,6 @@ static struct input_handler mousedev_han static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; static struct mousedev mousedev_mix; -static int mousedev_mix_open; #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03]) @@ -371,12 +371,11 @@ static void mixdev_release(void) { struct input_handle *handle; - mousedev_mix_open--; - list_for_each_entry(handle, &mousedev_handler.h_list, h_node) { struct mousedev *mousedev = handle->private; - input_close_device(handle); + if (!mousedev->open && mousedev->exist) + input_close_device(&mousedev->handle); kref_put(&mousedev->kref, mousedev_free); } } @@ -391,10 +390,12 @@ static int mousedev_release(struct inode list_del(&list->node); kfree(list); - if (mousedev->minor == MOUSEDEV_MIX) - mixdev_release(); - else - input_close_device(&mousedev->handle); + if (!--mousedev->open) { + if (mousedev->minor == MOUSEDEV_MIX) + mixdev_release(); + else if (!mousedev_mix.open && mousedev->exist) + input_close_device(&mousedev->handle); + } kref_put(&mousedev->kref, mousedev_free); @@ -406,7 +407,6 @@ static int mousedev_open(struct inode *i struct mousedev_list *list; struct input_handle *handle; struct mousedev *mousedev, *md; - int error; int i; #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX @@ -420,7 +420,7 @@ static int mousedev_open(struct inode *i return -ENODEV; mousedev = mousedev_table[i]; - if (!mousedev || mousedev->dead) + if (!mousedev || !mousedev->exist) return -ENODEV; list = kzalloc(sizeof(struct mousedev_list), GFP_KERNEL); @@ -436,21 +436,17 @@ static int mousedev_open(struct inode *i list_add_tail(&list->node, &mousedev->list); file->private_data = list; - if (mousedev->minor == MOUSEDEV_MIX) { - mousedev_mix_open++; - list_for_each_entry(handle, &mousedev_handler.h_list, h_node) { - md = handle->private; - kref_get(&md->kref); - input_open_device(handle); - } - } else { - error = input_open_device(&mousedev->handle); - if (error) { - list_del(&list->node); - kfree(list); - kref_put(&mousedev->kref, mousedev_free); - return error; - } + if (!mousedev->open++) { + if (mousedev->minor == MOUSEDEV_MIX) { + list_for_each_entry(handle, &mousedev_handler.h_list, h_node) { + md = handle->private; + kref_get(&md->kref); + if (!md->open && md->exist) + input_open_device(handle); + } + } else + if (!mousedev_mix.open && mousedev->exist) + input_open_device(&mousedev->handle); } return 0; @@ -585,19 +581,18 @@ static ssize_t mousedev_write(struct fil static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos) { struct mousedev_list *list = file->private_data; - struct mousedev *mousedev = list->mousedev; int retval = 0; if (!list->ready && !list->buffer && (file->f_flags & O_NONBLOCK)) return -EAGAIN; - retval = wait_event_interruptible(mousedev->wait, - mousedev->dead || list->ready || list->buffer); + retval = wait_event_interruptible(list->mousedev->wait, + !list->mousedev->exist || list->ready || list->buffer); if (retval) return retval; - if (mousedev->dead) + if (!list->mousedev->exist) return -ENODEV; if (!list->buffer && list->ready) { @@ -620,11 +615,10 @@ static ssize_t mousedev_read(struct file static unsigned int mousedev_poll(struct file *file, poll_table *wait) { struct mousedev_list *list = file->private_data; - struct mousedev *mousedev = list->mousedev; - poll_wait(file, &mousedev->wait, wait); - return (list->ready || list->buffer ? POLLIN | POLLRDNORM : 0) | - (mousedev->dead ? POLLHUP | POLLERR : 0); + poll_wait(file, &list->mousedev->wait, wait); + return ((list->ready || list->buffer) ? (POLLIN | POLLRDNORM) : 0) | + (list->mousedev->exist ? 0 : (POLLHUP | POLLERR)); } static const struct file_operations mousedev_fops = { @@ -661,6 +655,7 @@ static int mousedev_connect(struct input init_waitqueue_head(&mousedev->wait); mousedev->minor = minor; + mousedev->exist = 1; mousedev->handle.dev = dev; mousedev->handle.name = mousedev->name; mousedev->handle.handler = handler; @@ -686,7 +681,7 @@ static int mousedev_connect(struct input if (error) goto err_remove_link; - if (mousedev_mix_open) { + if (mousedev_mix.open) { error = input_open_device(&mousedev->handle); if (error) goto err_unlink_handle; @@ -716,11 +711,15 @@ static void mousedev_disconnect(struct i sysfs_remove_link(&input_class.subsys.kset.kobj, mousedev->name); class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); + mousedev->exist = 0; - mousedev->dead = 1; - wake_up_interruptible(&mousedev->wait); - list_for_each_entry(list, &mousedev->list, node) - kill_fasync(&list->fasync, SIGIO, POLL_HUP); + if (mousedev->open) { + input_close_device(handle); + wake_up_interruptible(&mousedev->wait); + list_for_each_entry(list, &mousedev->list, node) + kill_fasync(&list->fasync, SIGIO, POLL_HUP); + } else if (mousedev_mix.open) + input_close_device(handle); kref_put(&mousedev->kref, mousedev_free); } @@ -784,6 +783,7 @@ static int __init mousedev_init(void) kref_init(&mousedev_mix.kref); INIT_LIST_HEAD(&mousedev_mix.list); init_waitqueue_head(&mousedev_mix.wait); + mousedev_mix.exist = 1; mousedev_mix.minor = MOUSEDEV_MIX; mousedev_table[MOUSEDEV_MIX] = &mousedev_mix; diff -puN drivers/input/tsdev.c~revert-input-make-input_openclose_device-more-robust drivers/input/tsdev.c --- a/drivers/input/tsdev.c~revert-input-make-input_openclose_device-more-robust +++ a/drivers/input/tsdev.c @@ -106,7 +106,8 @@ struct ts_calibration { }; struct tsdev { - int dead; + int exist; + int open; int minor; char name[8]; struct input_handle handle; @@ -147,26 +148,17 @@ static int tsdev_fasync(int fd, struct f return retval < 0 ? retval : 0; } -static void tsdev_free(struct kref *kref) -{ - struct tsdev *tsdev = container_of(kref, struct tsdev, kref); - - tsdev_table[tsdev->minor] = NULL; - kfree(tsdev); -} - static int tsdev_open(struct inode *inode, struct file *file) { + int i = iminor(inode) - TSDEV_MINOR_BASE; struct tsdev_list *list; struct tsdev *tsdev; - int error; - int i = iminor(inode) - TSDEV_MINOR_BASE; if (i >= TSDEV_MINORS) return -ENODEV; tsdev = tsdev_table[i & TSDEV_MINOR_MASK]; - if (!tsdev || tsdev->dead) + if (!tsdev || !tsdev->exist) return -ENODEV; list = kzalloc(sizeof(struct tsdev_list), GFP_KERNEL); @@ -180,16 +172,18 @@ static int tsdev_open(struct inode *inod list_add_tail(&list->node, &tsdev->list); file->private_data = list; - error = input_open_device(&tsdev->handle); - if (error) - goto fail; + if (!tsdev->open++ && tsdev->exist) + input_open_device(&list->tsdev->handle); return 0; +} - fail: list_del(&list->node); - kfree(list); - kref_put(&tsdev->kref, tsdev_free); - return error; +static void tsdev_free(struct kref *kref) +{ + struct tsdev *tsdev = container_of(kref, struct tsdev, kref); + + tsdev_table[tsdev->minor] = NULL; + kfree(tsdev); } static int tsdev_release(struct inode *inode, struct file *file) @@ -202,7 +196,9 @@ static int tsdev_release(struct inode *i list_del(&list->node); kfree(list); - input_close_device(&tsdev->handle); + if (!--tsdev->open && tsdev->exist) + input_close_device(&tsdev->handle); + kref_put(&tsdev->kref, tsdev_free); return 0; @@ -215,16 +211,16 @@ static ssize_t tsdev_read(struct file *f struct tsdev *tsdev = list->tsdev; int retval = 0; - if (list->head == list->tail && !tsdev->dead && (file->f_flags & O_NONBLOCK)) + if (list->head == list->tail && tsdev->exist && (file->f_flags & O_NONBLOCK)) return -EAGAIN; retval = wait_event_interruptible(tsdev->wait, - list->head != list->tail || tsdev->dead); + list->head != list->tail || !tsdev->exist); if (retval) return retval; - if (tsdev->dead) + if (!tsdev->exist) return -ENODEV; while (list->head != list->tail && @@ -243,11 +239,10 @@ static ssize_t tsdev_read(struct file *f static unsigned int tsdev_poll(struct file *file, poll_table * wait) { struct tsdev_list *list = file->private_data; - struct tsdev *tsdev = list->tsdev; - poll_wait(file, &tsdev->wait, wait); - return (list->head != list->tail ? POLLIN | POLLRDNORM : 0) | - (tsdev->dead ? POLLHUP | POLLERR : 0); + poll_wait(file, &list->tsdev->wait, wait); + return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) | + (list->tsdev->exist ? 0 : (POLLHUP | POLLERR)); } static int tsdev_ioctl(struct inode *inode, struct file *file, @@ -409,6 +404,7 @@ static int tsdev_connect(struct input_ha sprintf(tsdev->name, "ts%d", minor); + tsdev->exist = 1; tsdev->minor = minor; tsdev->handle.dev = dev; tsdev->handle.name = tsdev->name; @@ -468,11 +464,14 @@ static void tsdev_disconnect(struct inpu sysfs_remove_link(&input_class.subsys.kset.kobj, tsdev->name); class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor)); + tsdev->exist = 0; - tsdev->dead = 1; - wake_up_interruptible(&tsdev->wait); - list_for_each_entry(list, &tsdev->list, node) - kill_fasync(&list->fasync, SIGIO, POLL_HUP); + if (tsdev->open) { + input_close_device(handle); + wake_up_interruptible(&tsdev->wait); + list_for_each_entry(list, &tsdev->list, node) + kill_fasync(&list->fasync, SIGIO, POLL_HUP); + } kref_put(&tsdev->kref, tsdev_free); } diff -puN include/linux/input.h~revert-input-make-input_openclose_device-more-robust include/linux/input.h --- a/include/linux/input.h~revert-input-make-input_openclose_device-more-robust +++ a/include/linux/input.h @@ -954,8 +954,7 @@ struct input_dev { struct timer_list timer; struct pt_regs *regs; - - int dead; + int state; int sync; _