Implementation for console control events (includes process groups
support).
diff --git a/server/console.c b/server/console.c
index 6ddd077..718d124 100644
--- a/server/console.c
+++ b/server/console.c
@@ -27,6 +27,7 @@
#include <string.h>
#include <stdio.h>
#include <unistd.h>
+#include <signal.h>
#include "handle.h"
#include "process.h"
@@ -385,6 +386,54 @@
return console->recnum ? 1 : 0;
}
+struct console_signal_info {
+ struct console_input *console;
+ struct process *group;
+ int signal;
+};
+
+static int propagate_console_signal_cb(struct process *process, void *user)
+{
+ struct console_signal_info* csi = (struct console_signal_info*)user;
+
+ if (process->console == csi->console && process->running_threads &&
+ (csi->group == NULL || process->group_id == csi->group))
+ {
+ struct thread *thread = process->thread_list;
+
+ while (thread)
+ {
+ struct thread *next = thread->proc_next;
+ kill( thread->unix_pid, csi->signal );
+ thread = next;
+ }
+ }
+ return FALSE;
+}
+
+static void propagate_console_signal( struct console_input *console,
+ int sig, void* group_id )
+{
+ struct console_signal_info csi;
+
+ if (!console)
+ {
+ set_error( STATUS_INVALID_PARAMETER );
+ return;
+ }
+ /* FIXME: should support the other events (like CTRL_BREAK) */
+ if (sig != CTRL_C_EVENT)
+ {
+ set_error( STATUS_NOT_IMPLEMENTED );
+ return;
+ }
+ csi.console = console;
+ csi.signal = SIGINT;
+ csi.group = group_id;
+
+ enum_processes(propagate_console_signal_cb, &csi);
+}
+
static int get_console_mode( obj_handle_t handle )
{
struct object *obj;
@@ -443,8 +492,31 @@
}
console->records = new_rec;
memcpy( new_rec + console->recnum, records, count * sizeof(INPUT_RECORD) );
- console->recnum += count;
+ if (console->mode & ENABLE_PROCESSED_INPUT)
+ {
+ int i = 0;
+ while (i < count)
+ {
+ if (records[i].EventType == KEY_EVENT &&
+ records[i].Event.KeyEvent.uChar.UnicodeChar == 'C' - 64 &&
+ !(records[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
+ {
+ if (i != count - 1)
+ memcpy( &console->records[console->recnum + i],
+ &console->records[console->recnum + i + 1],
+ (count - i - 1) * sizeof(INPUT_RECORD) );
+ count--;
+ if (records[i].Event.KeyEvent.bKeyDown)
+ {
+ /* send SIGINT to all processes attached to this console */
+ propagate_console_signal( console, CTRL_C_EVENT, NULL );
+ }
+ }
+ else i++;
+ }
+ }
+ console->recnum += count;
/* wake up all waiters */
wake_up( &console->obj, 0 );
return count;
@@ -1385,3 +1457,18 @@
scroll_console_output( req->handle, req->x_src, req->y_src, req->x_dst, req->y_dst,
req->w, req->h );
}
+
+/* sends a signal to a console (process, group...) */
+DECL_HANDLER(send_console_signal)
+{
+ void* group;
+
+ group = req->group_id ? req->group_id : current->process->group_id;
+
+ if (!group)
+ set_error( STATUS_INVALID_PARAMETER);
+ else
+ propagate_console_signal( current->process->console, req->signal, group );
+}
+
+
diff --git a/server/process.c b/server/process.c
index 0f89aa3..6a60569 100644
--- a/server/process.c
+++ b/server/process.c
@@ -218,6 +218,7 @@
process->exe.dbg_size = 0;
process->exe.namelen = 0;
process->exe.filename = NULL;
+ process->group_id = NULL;
gettimeofday( &process->start_time, NULL );
if ((process->next = first_process) != NULL) process->next->prev = process;
@@ -285,6 +286,7 @@
/* set the process console */
if (!set_process_console( process, parent_thread, info, reply )) return NULL;
+ process->group_id = process;
if (parent)
{
/* attach to the debugger if requested */
@@ -292,6 +294,8 @@
set_process_debugger( process, parent_thread );
else if (parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS))
set_process_debugger( process, parent->debugger );
+ if (!(process->create_flags & CREATE_NEW_PROCESS_GROUP))
+ process->group_id = parent->group_id;
}
/* thread will be actually suspended in init_done */
@@ -614,6 +618,16 @@
}
+void enum_processes( int (*cb)(struct process*, void*), void *user )
+{
+ struct process *process;
+ for (process = first_process; process; process = process->next)
+ {
+ if ((cb)(process, user)) break;
+ }
+}
+
+
/* get all information about a process */
static void get_process_info( struct process *process, struct get_process_info_reply *reply )
{
diff --git a/server/process.h b/server/process.h
index e320491..27ea25f 100644
--- a/server/process.h
+++ b/server/process.h
@@ -72,6 +72,7 @@
struct process_dll exe; /* main exe file */
void *ldt_copy; /* pointer to LDT copy in client addr space */
void *ldt_flags; /* pointer to LDT flags in client addr space */
+ void *group_id; /* group ID of the process */
};
struct process_snapshot
@@ -110,6 +111,7 @@
extern void detach_debugged_processes( struct thread *debugger );
extern struct process_snapshot *process_snap( int *count );
extern struct module_snapshot *module_snap( struct process *process, int *count );
+extern void enum_processes( int (*cb)(struct process*, void*), void *user);
inline static void *get_process_id( struct process *process ) { return process; }
inline static int is_process_init_done( struct process *process )
diff --git a/server/protocol.def b/server/protocol.def
index 8b68a43..9d4f8f3 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1009,6 +1009,7 @@
VARARG(data,bytes);
@END
+
/* move a rect (of data) in screen buffer content */
@REQ(move_console_output)
obj_handle_t handle; /* handle to the console output */
@@ -1021,6 +1022,13 @@
@END
+/* Sends a signal to a process group */
+@REQ(send_console_signal)
+ int signal; /* the signal to send */
+ void* group_id; /* the group to send the signal to */
+@END
+
+
/* Create a change notification */
@REQ(create_change_notification)
int subtree; /* watch all the subtree */
diff --git a/server/request.h b/server/request.h
index 94a659d..5f893ab 100644
--- a/server/request.h
+++ b/server/request.h
@@ -172,6 +172,7 @@
DECL_HANDLER(fill_console_output);
DECL_HANDLER(read_console_output);
DECL_HANDLER(move_console_output);
+DECL_HANDLER(send_console_signal);
DECL_HANDLER(create_change_notification);
DECL_HANDLER(create_mapping);
DECL_HANDLER(open_mapping);
@@ -333,6 +334,7 @@
(req_handler)req_fill_console_output,
(req_handler)req_read_console_output,
(req_handler)req_move_console_output,
+ (req_handler)req_send_console_signal,
(req_handler)req_create_change_notification,
(req_handler)req_create_mapping,
(req_handler)req_open_mapping,
diff --git a/server/trace.c b/server/trace.c
index b36cfa7..c96863d 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1191,6 +1191,12 @@
fprintf( stderr, " h=%d", req->h );
}
+static void dump_send_console_signal_request( const struct send_console_signal_request *req )
+{
+ fprintf( stderr, " signal=%d,", req->signal );
+ fprintf( stderr, " group_id=%p", req->group_id );
+}
+
static void dump_create_change_notification_request( const struct create_change_notification_request *req )
{
fprintf( stderr, " subtree=%d,", req->subtree );
@@ -2239,6 +2245,7 @@
(dump_func)dump_fill_console_output_request,
(dump_func)dump_read_console_output_request,
(dump_func)dump_move_console_output_request,
+ (dump_func)dump_send_console_signal_request,
(dump_func)dump_create_change_notification_request,
(dump_func)dump_create_mapping_request,
(dump_func)dump_open_mapping_request,
@@ -2397,6 +2404,7 @@
(dump_func)dump_fill_console_output_reply,
(dump_func)dump_read_console_output_reply,
(dump_func)0,
+ (dump_func)0,
(dump_func)dump_create_change_notification_reply,
(dump_func)dump_create_mapping_reply,
(dump_func)dump_open_mapping_reply,
@@ -2555,6 +2563,7 @@
"fill_console_output",
"read_console_output",
"move_console_output",
+ "send_console_signal",
"create_change_notification",
"create_mapping",
"open_mapping",