| /* |
| * Copyright (c) 2008-2011 Apple Inc. All rights reserved. |
| * |
| * @APPLE_APACHE_LICENSE_HEADER_START@ |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * @APPLE_APACHE_LICENSE_HEADER_END@ |
| */ |
| |
| #include <dispatch/dispatch.h> |
| #include <stdio.h> |
| #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) |
| #include <unistd.h> |
| #endif |
| #include <stdlib.h> |
| #include <assert.h> |
| #include <spawn.h> |
| #include <signal.h> |
| #ifdef __APPLE__ |
| #include <libkern/OSAtomic.h> |
| #endif |
| |
| #include <bsdtests.h> |
| #include "dispatch_test.h" |
| |
| #define PID_CNT 5 |
| |
| static long event_cnt; |
| |
| void |
| test_proc(pid_t bad_pid) |
| { |
| dispatch_source_t proc_s[PID_CNT], proc; |
| int res; |
| pid_t pid, monitor_pid; |
| |
| event_cnt = 0; |
| // Creates a process and register multiple observers. Send a signal, |
| // exit the process, etc., and verify all observers were notified. |
| |
| posix_spawnattr_t attr; |
| res = posix_spawnattr_init(&attr); |
| assert(res == 0); |
| res = posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED); |
| assert(res == 0); |
| |
| char* args[] = { |
| "/bin/sleep", "2", NULL |
| }; |
| |
| res = posix_spawnp(&pid, args[0], NULL, &attr, args, NULL); |
| if (res < 0) { |
| perror(args[0]); |
| exit(127); |
| } |
| |
| res = posix_spawnattr_destroy(&attr); |
| assert(res == 0); |
| |
| dispatch_group_t group = dispatch_group_create(); |
| |
| assert(pid > 0); |
| monitor_pid = bad_pid ? bad_pid : pid; // rdar://problem/8090801 |
| |
| int i; |
| for (i = 0; i < PID_CNT; ++i) { |
| dispatch_group_enter(group); |
| proc = proc_s[i] = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, |
| monitor_pid, DISPATCH_PROC_EXIT, dispatch_get_global_queue(0, 0)); |
| test_ptr_notnull("dispatch_source_proc_create", proc); |
| dispatch_source_set_event_handler(proc, ^{ |
| long flags = dispatch_source_get_data(proc); |
| test_long("DISPATCH_PROC_EXIT", flags, DISPATCH_PROC_EXIT); |
| event_cnt++; |
| dispatch_source_cancel(proc); |
| }); |
| dispatch_source_set_cancel_handler(proc, ^{ |
| dispatch_group_leave(group); |
| }); |
| dispatch_resume(proc); |
| } |
| kill(pid, SIGCONT); |
| if (dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 10*NSEC_PER_SEC))) { |
| for (i = 0; i < PID_CNT; ++i) { |
| dispatch_source_cancel(proc_s[i]); |
| } |
| dispatch_group_wait(group, DISPATCH_TIME_FOREVER); |
| } |
| for (i = 0; i < PID_CNT; ++i) { |
| dispatch_release(proc_s[i]); |
| } |
| dispatch_release(group); |
| // delay 5 seconds to give a chance for any bugs that |
| // result in too many events to be noticed |
| dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5*NSEC_PER_SEC), dispatch_get_main_queue(), ^{ |
| int status; |
| int res2 = waitpid(pid, &status, 0); |
| assert(res2 != -1); |
| //int passed = (WIFEXITED(status) && WEXITSTATUS(status) == 0); |
| test_long("Sub-process exited", WEXITSTATUS(status) | WTERMSIG(status), 0); |
| test_long("Event count", event_cnt, PID_CNT); |
| if (bad_pid) { |
| test_stop(); |
| } else { |
| dispatch_async(dispatch_get_main_queue(), ^{ |
| test_proc(pid); |
| }); |
| } |
| }); |
| } |
| |
| int |
| main(void) |
| { |
| dispatch_test_start("Dispatch Proc"); |
| test_proc(0); |
| dispatch_main(); |
| |
| return 0; |
| } |