diff options
| author | Eli Zaretskii | 2012-11-17 20:00:16 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2012-11-17 20:00:16 +0200 |
| commit | cf2d22b874ca2df0072e32ee641e8efffe4abd6d (patch) | |
| tree | 1795142ec7861fc85c61adc90f03265b69041556 /src/w32proc.c | |
| parent | 3c4ca7155293ffc2d04708007131bcbc882d8913 (diff) | |
| parent | 6ad30855c02908fdd99d9b11943719e185e65ee3 (diff) | |
| download | emacs-cf2d22b874ca2df0072e32ee641e8efffe4abd6d.tar.gz emacs-cf2d22b874ca2df0072e32ee641e8efffe4abd6d.zip | |
Merge from trunk.
Diffstat (limited to 'src/w32proc.c')
| -rw-r--r-- | src/w32proc.c | 165 |
1 files changed, 116 insertions, 49 deletions
diff --git a/src/w32proc.c b/src/w32proc.c index e074ece020d..2951df7ed89 100644 --- a/src/w32proc.c +++ b/src/w32proc.c | |||
| @@ -431,13 +431,14 @@ timer_loop (LPVOID arg) | |||
| 431 | /* Simulate a signal delivered to the thread which installed | 431 | /* Simulate a signal delivered to the thread which installed |
| 432 | the timer, by suspending that thread while the handler | 432 | the timer, by suspending that thread while the handler |
| 433 | runs. */ | 433 | runs. */ |
| 434 | DWORD result = SuspendThread (itimer->caller_thread); | 434 | HANDLE th = itimer->caller_thread; |
| 435 | DWORD result = SuspendThread (th); | ||
| 435 | 436 | ||
| 436 | if (result == (DWORD)-1) | 437 | if (result == (DWORD)-1) |
| 437 | return 2; | 438 | return 2; |
| 438 | 439 | ||
| 439 | handler (sig); | 440 | handler (sig); |
| 440 | ResumeThread (itimer->caller_thread); | 441 | ResumeThread (th); |
| 441 | } | 442 | } |
| 442 | 443 | ||
| 443 | /* Update expiration time and loop. */ | 444 | /* Update expiration time and loop. */ |
| @@ -562,6 +563,7 @@ static int | |||
| 562 | start_timer_thread (int which) | 563 | start_timer_thread (int which) |
| 563 | { | 564 | { |
| 564 | DWORD exit_code; | 565 | DWORD exit_code; |
| 566 | HANDLE th; | ||
| 565 | struct itimer_data *itimer = | 567 | struct itimer_data *itimer = |
| 566 | (which == ITIMER_REAL) ? &real_itimer : &prof_itimer; | 568 | (which == ITIMER_REAL) ? &real_itimer : &prof_itimer; |
| 567 | 569 | ||
| @@ -570,9 +572,29 @@ start_timer_thread (int which) | |||
| 570 | && exit_code == STILL_ACTIVE) | 572 | && exit_code == STILL_ACTIVE) |
| 571 | return 0; | 573 | return 0; |
| 572 | 574 | ||
| 575 | /* Clean up after possibly exited thread. */ | ||
| 576 | if (itimer->timer_thread) | ||
| 577 | { | ||
| 578 | CloseHandle (itimer->timer_thread); | ||
| 579 | itimer->timer_thread = NULL; | ||
| 580 | } | ||
| 581 | if (itimer->caller_thread) | ||
| 582 | { | ||
| 583 | CloseHandle (itimer->caller_thread); | ||
| 584 | itimer->caller_thread = NULL; | ||
| 585 | } | ||
| 586 | |||
| 573 | /* Start a new thread. */ | 587 | /* Start a new thread. */ |
| 588 | if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), | ||
| 589 | GetCurrentProcess (), &th, 0, FALSE, | ||
| 590 | DUPLICATE_SAME_ACCESS)) | ||
| 591 | { | ||
| 592 | errno = ESRCH; | ||
| 593 | return -1; | ||
| 594 | } | ||
| 574 | itimer->terminate = 0; | 595 | itimer->terminate = 0; |
| 575 | itimer->type = which; | 596 | itimer->type = which; |
| 597 | itimer->caller_thread = th; | ||
| 576 | /* Request that no more than 64KB of stack be reserved for this | 598 | /* Request that no more than 64KB of stack be reserved for this |
| 577 | thread, to avoid reserving too much memory, which would get in | 599 | thread, to avoid reserving too much memory, which would get in |
| 578 | the way of threads we start to wait for subprocesses. See also | 600 | the way of threads we start to wait for subprocesses. See also |
| @@ -591,7 +613,7 @@ start_timer_thread (int which) | |||
| 591 | /* This is needed to make sure that the timer thread running for | 613 | /* This is needed to make sure that the timer thread running for |
| 592 | profiling gets CPU as soon as the Sleep call terminates. */ | 614 | profiling gets CPU as soon as the Sleep call terminates. */ |
| 593 | if (which == ITIMER_PROF) | 615 | if (which == ITIMER_PROF) |
| 594 | SetThreadPriority (itimer->caller_thread, THREAD_PRIORITY_TIME_CRITICAL); | 616 | SetThreadPriority (itimer->timer_thread, THREAD_PRIORITY_TIME_CRITICAL); |
| 595 | 617 | ||
| 596 | return 0; | 618 | return 0; |
| 597 | } | 619 | } |
| @@ -626,17 +648,9 @@ getitimer (int which, struct itimerval *value) | |||
| 626 | 648 | ||
| 627 | itimer = (which == ITIMER_REAL) ? &real_itimer : &prof_itimer; | 649 | itimer = (which == ITIMER_REAL) ? &real_itimer : &prof_itimer; |
| 628 | 650 | ||
| 629 | if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), | ||
| 630 | GetCurrentProcess (), &itimer->caller_thread, 0, | ||
| 631 | FALSE, DUPLICATE_SAME_ACCESS)) | ||
| 632 | { | ||
| 633 | errno = ESRCH; | ||
| 634 | return -1; | ||
| 635 | } | ||
| 636 | |||
| 637 | ticks_now = w32_get_timer_time ((which == ITIMER_REAL) | 651 | ticks_now = w32_get_timer_time ((which == ITIMER_REAL) |
| 638 | ? NULL | 652 | ? NULL |
| 639 | : itimer->caller_thread); | 653 | : GetCurrentThread ()); |
| 640 | 654 | ||
| 641 | t_expire = &itimer->expire; | 655 | t_expire = &itimer->expire; |
| 642 | t_reload = &itimer->reload; | 656 | t_reload = &itimer->reload; |
| @@ -775,7 +789,6 @@ alarm (int seconds) | |||
| 775 | /* Child process management list. */ | 789 | /* Child process management list. */ |
| 776 | int child_proc_count = 0; | 790 | int child_proc_count = 0; |
| 777 | child_process child_procs[ MAX_CHILDREN ]; | 791 | child_process child_procs[ MAX_CHILDREN ]; |
| 778 | child_process *dead_child = NULL; | ||
| 779 | 792 | ||
| 780 | static DWORD WINAPI reader_thread (void *arg); | 793 | static DWORD WINAPI reader_thread (void *arg); |
| 781 | 794 | ||
| @@ -1028,9 +1041,6 @@ create_child (char *exe, char *cmdline, char *env, int is_gui_app, | |||
| 1028 | if (cp->pid < 0) | 1041 | if (cp->pid < 0) |
| 1029 | cp->pid = -cp->pid; | 1042 | cp->pid = -cp->pid; |
| 1030 | 1043 | ||
| 1031 | /* pid must fit in a Lisp_Int */ | ||
| 1032 | cp->pid = cp->pid & INTMASK; | ||
| 1033 | |||
| 1034 | *pPid = cp->pid; | 1044 | *pPid = cp->pid; |
| 1035 | 1045 | ||
| 1036 | return TRUE; | 1046 | return TRUE; |
| @@ -1106,55 +1116,110 @@ reap_subprocess (child_process *cp) | |||
| 1106 | delete_child (cp); | 1116 | delete_child (cp); |
| 1107 | } | 1117 | } |
| 1108 | 1118 | ||
| 1109 | /* Wait for any of our existing child processes to die | 1119 | /* Wait for a child process specified by PID, or for any of our |
| 1110 | When it does, close its handle | 1120 | existing child processes (if PID is nonpositive) to die. When it |
| 1111 | Return the pid and fill in the status if non-NULL. */ | 1121 | does, close its handle. Return the pid of the process that died |
| 1122 | and fill in STATUS if non-NULL. */ | ||
| 1112 | 1123 | ||
| 1113 | int | 1124 | pid_t |
| 1114 | sys_wait (int *status) | 1125 | waitpid (pid_t pid, int *status, int options) |
| 1115 | { | 1126 | { |
| 1116 | DWORD active, retval; | 1127 | DWORD active, retval; |
| 1117 | int nh; | 1128 | int nh; |
| 1118 | int pid; | ||
| 1119 | child_process *cp, *cps[MAX_CHILDREN]; | 1129 | child_process *cp, *cps[MAX_CHILDREN]; |
| 1120 | HANDLE wait_hnd[MAX_CHILDREN]; | 1130 | HANDLE wait_hnd[MAX_CHILDREN]; |
| 1131 | DWORD timeout_ms; | ||
| 1132 | int dont_wait = (options & WNOHANG) != 0; | ||
| 1121 | 1133 | ||
| 1122 | nh = 0; | 1134 | nh = 0; |
| 1123 | if (dead_child != NULL) | 1135 | /* According to Posix: |
| 1136 | |||
| 1137 | PID = -1 means status is requested for any child process. | ||
| 1138 | |||
| 1139 | PID > 0 means status is requested for a single child process | ||
| 1140 | whose pid is PID. | ||
| 1141 | |||
| 1142 | PID = 0 means status is requested for any child process whose | ||
| 1143 | process group ID is equal to that of the calling process. But | ||
| 1144 | since Windows has only a limited support for process groups (only | ||
| 1145 | for console processes and only for the purposes of passing | ||
| 1146 | Ctrl-BREAK signal to them), and since we have no documented way | ||
| 1147 | of determining whether a given process belongs to our group, we | ||
| 1148 | treat 0 as -1. | ||
| 1149 | |||
| 1150 | PID < -1 means status is requested for any child process whose | ||
| 1151 | process group ID is equal to the absolute value of PID. Again, | ||
| 1152 | since we don't support process groups, we treat that as -1. */ | ||
| 1153 | if (pid > 0) | ||
| 1124 | { | 1154 | { |
| 1125 | /* We want to wait for a specific child */ | 1155 | int our_child = 0; |
| 1126 | wait_hnd[nh] = dead_child->procinfo.hProcess; | 1156 | |
| 1127 | cps[nh] = dead_child; | 1157 | /* We are requested to wait for a specific child. */ |
| 1128 | if (!wait_hnd[nh]) emacs_abort (); | 1158 | for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--) |
| 1129 | nh++; | 1159 | { |
| 1130 | active = 0; | 1160 | /* Some child_procs might be sockets; ignore them. Also |
| 1131 | goto get_result; | 1161 | ignore subprocesses whose output is not yet completely |
| 1162 | read. */ | ||
| 1163 | if (CHILD_ACTIVE (cp) | ||
| 1164 | && cp->procinfo.hProcess | ||
| 1165 | && cp->pid == pid) | ||
| 1166 | { | ||
| 1167 | our_child = 1; | ||
| 1168 | break; | ||
| 1169 | } | ||
| 1170 | } | ||
| 1171 | if (our_child) | ||
| 1172 | { | ||
| 1173 | if (cp->fd < 0 || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0) | ||
| 1174 | { | ||
| 1175 | wait_hnd[nh] = cp->procinfo.hProcess; | ||
| 1176 | cps[nh] = cp; | ||
| 1177 | nh++; | ||
| 1178 | } | ||
| 1179 | else if (dont_wait) | ||
| 1180 | { | ||
| 1181 | /* PID specifies our subprocess, but its status is not | ||
| 1182 | yet available. */ | ||
| 1183 | return 0; | ||
| 1184 | } | ||
| 1185 | } | ||
| 1186 | if (nh == 0) | ||
| 1187 | { | ||
| 1188 | /* No such child process, or nothing to wait for, so fail. */ | ||
| 1189 | errno = ECHILD; | ||
| 1190 | return -1; | ||
| 1191 | } | ||
| 1132 | } | 1192 | } |
| 1133 | else | 1193 | else |
| 1134 | { | 1194 | { |
| 1135 | for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--) | 1195 | for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--) |
| 1136 | /* some child_procs might be sockets; ignore them */ | 1196 | { |
| 1137 | if (CHILD_ACTIVE (cp) && cp->procinfo.hProcess | 1197 | if (CHILD_ACTIVE (cp) |
| 1138 | && (cp->fd < 0 || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0)) | 1198 | && cp->procinfo.hProcess |
| 1139 | { | 1199 | && (cp->fd < 0 || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0)) |
| 1140 | wait_hnd[nh] = cp->procinfo.hProcess; | 1200 | { |
| 1141 | cps[nh] = cp; | 1201 | wait_hnd[nh] = cp->procinfo.hProcess; |
| 1142 | nh++; | 1202 | cps[nh] = cp; |
| 1143 | } | 1203 | nh++; |
| 1204 | } | ||
| 1205 | } | ||
| 1206 | if (nh == 0) | ||
| 1207 | { | ||
| 1208 | /* Nothing to wait on, so fail. */ | ||
| 1209 | errno = ECHILD; | ||
| 1210 | return -1; | ||
| 1211 | } | ||
| 1144 | } | 1212 | } |
| 1145 | 1213 | ||
| 1146 | if (nh == 0) | 1214 | if (dont_wait) |
| 1147 | { | 1215 | timeout_ms = 0; |
| 1148 | /* Nothing to wait on, so fail */ | 1216 | else |
| 1149 | errno = ECHILD; | 1217 | timeout_ms = 1000; /* check for quit about once a second. */ |
| 1150 | return -1; | ||
| 1151 | } | ||
| 1152 | 1218 | ||
| 1153 | do | 1219 | do |
| 1154 | { | 1220 | { |
| 1155 | /* Check for quit about once a second. */ | ||
| 1156 | QUIT; | 1221 | QUIT; |
| 1157 | active = WaitForMultipleObjects (nh, wait_hnd, FALSE, 1000); | 1222 | active = WaitForMultipleObjects (nh, wait_hnd, FALSE, timeout_ms); |
| 1158 | } while (active == WAIT_TIMEOUT); | 1223 | } while (active == WAIT_TIMEOUT); |
| 1159 | 1224 | ||
| 1160 | if (active == WAIT_FAILED) | 1225 | if (active == WAIT_FAILED) |
| @@ -1184,8 +1249,10 @@ get_result: | |||
| 1184 | } | 1249 | } |
| 1185 | if (retval == STILL_ACTIVE) | 1250 | if (retval == STILL_ACTIVE) |
| 1186 | { | 1251 | { |
| 1187 | /* Should never happen */ | 1252 | /* Should never happen. */ |
| 1188 | DebPrint (("Wait.WaitForMultipleObjects returned an active process\n")); | 1253 | DebPrint (("Wait.WaitForMultipleObjects returned an active process\n")); |
| 1254 | if (pid > 0 && dont_wait) | ||
| 1255 | return 0; | ||
| 1189 | errno = EINVAL; | 1256 | errno = EINVAL; |
| 1190 | return -1; | 1257 | return -1; |
| 1191 | } | 1258 | } |
| @@ -1199,6 +1266,8 @@ get_result: | |||
| 1199 | else | 1266 | else |
| 1200 | retval <<= 8; | 1267 | retval <<= 8; |
| 1201 | 1268 | ||
| 1269 | if (pid > 0 && active != 0) | ||
| 1270 | emacs_abort (); | ||
| 1202 | cp = cps[active]; | 1271 | cp = cps[active]; |
| 1203 | pid = cp->pid; | 1272 | pid = cp->pid; |
| 1204 | #ifdef FULL_DEBUG | 1273 | #ifdef FULL_DEBUG |
| @@ -2004,9 +2073,7 @@ count_children: | |||
| 2004 | DebPrint (("select calling SIGCHLD handler for pid %d\n", | 2073 | DebPrint (("select calling SIGCHLD handler for pid %d\n", |
| 2005 | cp->pid)); | 2074 | cp->pid)); |
| 2006 | #endif | 2075 | #endif |
| 2007 | dead_child = cp; | ||
| 2008 | sig_handlers[SIGCHLD] (SIGCHLD); | 2076 | sig_handlers[SIGCHLD] (SIGCHLD); |
| 2009 | dead_child = NULL; | ||
| 2010 | } | 2077 | } |
| 2011 | } | 2078 | } |
| 2012 | else if (fdindex[active] == -1) | 2079 | else if (fdindex[active] == -1) |