.enable_mask = SYSRQ_ENABLE_RTNICE,
};
+/* send a signal to a process named comm if it has a certain parent */
+/* if parent is NULL, send to the first matching process */
+static void sysrq_x_cros_signal_process(char *comm, char *parent, int sig)
+{
+ struct task_struct *p;
+
+ read_lock(&tasklist_lock);
+ for_each_process(p) {
+ if (p->flags & PF_KTHREAD)
+ continue;
+ if (is_global_init(p))
+ continue;
+
+ if (!strncmp(p->comm, comm, TASK_COMM_LEN)) {
+ if (!parent) {
+ printk(KERN_INFO
+ "%s: signal %d %s pid %u tgid %u\n",
+ __func__, sig, comm, p->pid, p->tgid);
+ do_send_sig_info(sig, SEND_SIG_FORCED, p,
+ true);
+ break;
+ } else if (p->parent &&
+ !strncmp(p->parent->comm, parent,
+ TASK_COMM_LEN)) {
+ printk(KERN_INFO
+ "%s: signal %d %s with parent %s "
+ "pid %u tgid %u\n",
+ __func__, sig,
+ comm, parent, p->parent->pid,
+ p->parent->tgid);
+ do_send_sig_info(sig, SEND_SIG_FORCED, p,
+ true);
+ break;
+ }
+ }
+ }
+ read_unlock(&tasklist_lock);
+}
+
+/* how many seconds do we wait for subsequent keypresses after the first */
+#define CROS_SYSRQ_WAIT 20
+
static void sysrq_handle_cros_xkey(int key)
{
- sysrq_handle_showstate_blocked(key);
- sysrq_handle_sync(key);
- mdelay(1000); /* Delay for a bit to give time for sync to complete */
- panic("ChromeOS X Key");
+ static unsigned long first_jiffies;
+ static unsigned int xkey_iteration;
+
+ if ((!first_jiffies) ||
+ (jiffies - first_jiffies) > CROS_SYSRQ_WAIT * HZ) {
+ first_jiffies = jiffies;
+ xkey_iteration = 0;
+ } else
+ xkey_iteration++;
+
+ if (!xkey_iteration)
+ sysrq_x_cros_signal_process("chrome", "session_manager",
+ SIGABRT);
+ else if (xkey_iteration == 1)
+ sysrq_x_cros_signal_process("X", NULL, SIGABRT);
+ else {
+ sysrq_handle_showstate_blocked(key);
+ sysrq_handle_sync(key);
+ /* Delay for a bit to give time for sync to complete */
+ mdelay(1000);
+ panic("ChromeOS X Key");
+ }
}
static struct sysrq_key_op sysrq_cros_xkey = {