int main(int argc,char **argv) { struct cmdlineInfo cmdline; unsigned int i; pbm_init(&argc, argv); parseCommandLine(argc, argv, &cmdline); sent_xon = FALSE; for (i = 0; i < cmdline.nFiles; ++i) { FILE *ifP; pm_message("opening '%s'", cmdline.inputFile[i]); ifP = pm_openr(cmdline.inputFile[i]); process_handle(ifP, cmdline.graph_mode, cmdline.passes); pm_close(ifP); } free(cmdline.inputFile); return 0; }
int launch_server(const std::string& socket_spec) { #if defined(_WIN32) /* we need to start the server in the background */ /* we create a PIPE that will be used to wait for the server's "OK" */ /* message since the pipe handles must be inheritable, we use a */ /* security attribute */ SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; // Redirect stdin to Windows /dev/null. If we instead pass an original // stdin/stdout/stderr handle and it is a console handle, when the adb // server starts up, the C Runtime will see a console handle for a process // that isn't connected to a console and it will configure // stdin/stdout/stderr to be closed. At that point, freopen() could be used // to reopen stderr/out, but it would take more massaging to fixup the file // descriptor number that freopen() uses. It's simplest to avoid all of this // complexity by just redirecting stdin to `nul' and then the C Runtime acts // as expected. unique_handle nul_read(CreateFileW(L"nul", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); if (nul_read.get() == INVALID_HANDLE_VALUE) { fprintf(stderr, "Cannot open 'nul': %s\n", android::base::SystemErrorCodeToString(GetLastError()).c_str()); return -1; } // Create pipes with non-inheritable read handle, inheritable write handle. We need to connect // the subprocess to pipes instead of just letting the subprocess inherit our existing // stdout/stderr handles because a DETACHED_PROCESS cannot write to a console that it is not // attached to. unique_handle ack_read, ack_write; if (!_create_anonymous_pipe(&ack_read, &ack_write, &sa)) { return -1; } unique_handle stdout_read, stdout_write; if (!_create_anonymous_pipe(&stdout_read, &stdout_write, &sa)) { return -1; } unique_handle stderr_read, stderr_write; if (!_create_anonymous_pipe(&stderr_read, &stderr_write, &sa)) { return -1; } /* Some programs want to launch an adb command and collect its output by * calling CreateProcess with inheritable stdout/stderr handles, then * using read() to get its output. When this happens, the stdout/stderr * handles passed to the adb client process will also be inheritable. * When starting the adb server here, care must be taken to reset them * to non-inheritable. * Otherwise, something bad happens: even if the adb command completes, * the calling process is stuck while read()-ing from the stdout/stderr * descriptors, because they're connected to corresponding handles in the * adb server process (even if the latter never uses/writes to them). * Note that even if we don't pass these handles in the STARTUPINFO struct, * if they're marked inheritable, they're still inherited, requiring us to * deal with this. * * If we're still having problems with inheriting random handles in the * future, consider using PROC_THREAD_ATTRIBUTE_HANDLE_LIST to explicitly * specify which handles should be inherited: http://blogs.msdn.com/b/oldnewthing/archive/2011/12/16/10248328.aspx * * Older versions of Windows return console pseudo-handles that cannot be * made non-inheritable, so ignore those failures. */ _try_make_handle_noninheritable(GetStdHandle(STD_INPUT_HANDLE)); _try_make_handle_noninheritable(GetStdHandle(STD_OUTPUT_HANDLE)); _try_make_handle_noninheritable(GetStdHandle(STD_ERROR_HANDLE)); STARTUPINFOW startup; ZeroMemory( &startup, sizeof(startup) ); startup.cb = sizeof(startup); startup.hStdInput = nul_read.get(); startup.hStdOutput = stdout_write.get(); startup.hStdError = stderr_write.get(); startup.dwFlags = STARTF_USESTDHANDLES; // Verify that the pipe_write handle value can be passed on the command line // as %d and that the rest of adb code can pass it around in an int. const int ack_write_as_int = cast_handle_to_int(ack_write.get()); if (cast_int_to_handle(ack_write_as_int) != ack_write.get()) { // If this fires, either handle values are larger than 32-bits or else // there is a bug in our casting. // https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203%28v=vs.85%29.aspx fprintf(stderr, "Cannot fit pipe handle value into 32-bits: 0x%p\n", ack_write.get()); return -1; } // get path of current program WCHAR program_path[MAX_PATH]; const DWORD module_result = GetModuleFileNameW(NULL, program_path, arraysize(program_path)); if ((module_result >= arraysize(program_path)) || (module_result == 0)) { // String truncation or some other error. fprintf(stderr, "Cannot get executable path: %s\n", android::base::SystemErrorCodeToString(GetLastError()).c_str()); return -1; } WCHAR args[64]; snwprintf(args, arraysize(args), L"adb -L %s fork-server server --reply-fd %d", socket_spec.c_str(), ack_write_as_int); PROCESS_INFORMATION pinfo; ZeroMemory(&pinfo, sizeof(pinfo)); if (!CreateProcessW( program_path, /* program path */ args, /* the fork-server argument will set the debug = 2 in the child */ NULL, /* process handle is not inheritable */ NULL, /* thread handle is not inheritable */ TRUE, /* yes, inherit some handles */ DETACHED_PROCESS, /* the new process doesn't have a console */ NULL, /* use parent's environment block */ NULL, /* use parent's starting directory */ &startup, /* startup info, i.e. std handles */ &pinfo )) { fprintf(stderr, "Cannot create process: %s\n", android::base::SystemErrorCodeToString(GetLastError()).c_str()); return -1; } unique_handle process_handle(pinfo.hProcess); pinfo.hProcess = NULL; // Close handles that we no longer need to complete the rest. CloseHandle(pinfo.hThread); pinfo.hThread = NULL; nul_read.reset(); ack_write.reset(); stdout_write.reset(); stderr_write.reset(); // Start threads to read from subprocess stdout/stderr and write to ours to make subprocess // errors easier to diagnose. Note that the threads internally create inheritable handles, but // that is ok because we've already spawned the subprocess. // In the past, reading from a pipe before the child process's C Runtime // started up and called GetFileType() caused a hang: http://blogs.msdn.com/b/oldnewthing/archive/2011/12/02/10243553.aspx#10244216 // This is reportedly fixed in Windows Vista: https://support.microsoft.com/en-us/kb/2009703 // I was unable to reproduce the problem on Windows XP. It sounds like a // Windows Update may have fixed this: https://www.duckware.com/tech/peeknamedpipe.html unique_handle stdout_thread(reinterpret_cast<HANDLE>( _beginthreadex(NULL, 0, _redirect_stdout_thread, stdout_read.get(), 0, NULL))); if (stdout_thread.get() == nullptr) { fprintf(stderr, "Cannot create thread: %s\n", strerror(errno)); return -1; } stdout_read.release(); // Transfer ownership to new thread unique_handle stderr_thread(reinterpret_cast<HANDLE>( _beginthreadex(NULL, 0, _redirect_stderr_thread, stderr_read.get(), 0, NULL))); if (stderr_thread.get() == nullptr) { fprintf(stderr, "Cannot create thread: %s\n", strerror(errno)); return -1; } stderr_read.release(); // Transfer ownership to new thread bool got_ack = false; // Wait for the "OK\n" message, for the pipe to be closed, or other error. { char temp[3]; DWORD count = 0; if (ReadFile(ack_read.get(), temp, sizeof(temp), &count, NULL)) { const CHAR expected[] = "OK\n"; const DWORD expected_length = arraysize(expected) - 1; if (count == expected_length && memcmp(temp, expected, expected_length) == 0) { got_ack = true; } else { fprintf(stderr, "ADB server didn't ACK\n"); } } else { const DWORD err = GetLastError(); // If the ACK was not written and the process exited, GetLastError() // is probably ERROR_BROKEN_PIPE, in which case that info is not // useful to the user. fprintf(stderr, "could not read ok from ADB Server%s\n", err == ERROR_BROKEN_PIPE ? "" : android::base::StringPrintf(": %s", android::base::SystemErrorCodeToString(err).c_str()).c_str()); } } // Always try to wait a bit for threads reading stdout/stderr to finish. // If the process started ok, it should close the pipes causing the threads // to finish. If the process had an error, it should exit, also causing // the pipes to be closed. In that case we want to read all of the output // and write it out so that the user can diagnose failures. const DWORD thread_timeout_ms = 15 * 1000; const HANDLE threads[] = { stdout_thread.get(), stderr_thread.get() }; const DWORD wait_result = WaitForMultipleObjects(arraysize(threads), threads, TRUE, thread_timeout_ms); if (wait_result == WAIT_TIMEOUT) { // Threads did not finish after waiting a little while. Perhaps the // server didn't close pipes, or it is hung. fprintf(stderr, "Timed-out waiting for threads to finish reading from " "ADB Server\n"); // Process handles are signaled when the process exits, so if we wait // on the handle for 0 seconds and it returns 'timeout', that means that // the process is still running. if (WaitForSingleObject(process_handle.get(), 0) == WAIT_TIMEOUT) { // We could TerminateProcess(), but that seems somewhat presumptive. fprintf(stderr, "ADB Server is running: process id %lu\n", pinfo.dwProcessId); } return -1; } if (wait_result != WAIT_OBJECT_0) { fprintf(stderr, "Unexpected result waiting for threads: %lu: %s\n", wait_result, android::base::SystemErrorCodeToString(GetLastError()).c_str()); return -1; } // For now ignore the thread exit codes and assume they worked properly. if (!got_ack) { return -1; } #else /* !defined(_WIN32) */ // set up a pipe so the child can tell us when it is ready. // fd[0] will be parent's end, and the child will write on fd[1] int fd[2]; if (pipe(fd)) { fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno); return -1; } std::string path = android::base::GetExecutablePath(); pid_t pid = fork(); if (pid < 0) return -1; if (pid == 0) { // child side of the fork adb_close(fd[0]); char reply_fd[30]; snprintf(reply_fd, sizeof(reply_fd), "%d", fd[1]); // child process int result = execl(path.c_str(), "adb", "-L", socket_spec.c_str(), "fork-server", "server", "--reply-fd", reply_fd, NULL); // this should not return fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno); } else { // parent side of the fork char temp[3]; temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C'; // wait for the "OK\n" message adb_close(fd[1]); int ret = adb_read(fd[0], temp, 3); int saved_errno = errno; adb_close(fd[0]); if (ret < 0) { fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_errno); return -1; } if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') { fprintf(stderr, "ADB server didn't ACK\n" ); return -1; } } #endif /* !defined(_WIN32) */ return 0; }
/** * Process incoming packets. */ int inic_data_loop(void) { cvm_common_wqe_t *swp = NULL; cvm_tcp_in_endpoints_t conn; cvm_tcp_tcphdr_t *th = NULL; cvm_ip_ip_t *ih = NULL; cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get(); uint64_t cpu_clock_hz = sys_info_ptr->cpu_clock_hz; uint64_t tick_cycle = cvmx_get_cycle(); uint64_t tick_step; uint32_t idle_processing_interval_ticks = (CVM_COMMON_IDLE_PROCESSING_INTERVAL)*(1000*1000)/(CVM_COMMON_TICK_LEN_US); uint32_t idle_processing_last_ticks = 0; #ifdef INET6 struct cvm_ip6_ip6_hdr *ip6 = NULL; #ifdef CVM_ENET_TUNNEL struct cvm_ip6_ip6_hdr *i6h = NULL; #endif #endif #ifdef CVM_CLI_APP uint64_t idle_cycle_start_value; #endif /* for the simulator */ if (cpu_clock_hz == 0) { cpu_clock_hz = 333000000; } tick_step = (CVM_COMMON_TICK_LEN_US * cpu_clock_hz) / 1000000; cvm_debug_print_interval = cpu_clock_hz; #ifndef REAL_HW /* for the simulator, set the debug interval to be 3M cycles */ cvm_debug_print_interval = 3000000; #endif #ifdef DUTY_CYCLE start_cycle = cvmx_get_cycle(); process_count = 0; #endif if (cvmx_coremask_first_core(coremask_data)) { /* Initiate a timer transaction for arp entry timeouts */ //if(cvm_enet_arp_timeout_init() != CVMX_TIM_STATUS_SUCCESS) //{ // printf("Failed init of cvm_ip_arp_timeout_init\n"); //} } #if defined(CVM_COMBINED_APP_STACK) /* Flush the packets sent by main_global and main_local */ /* printf("before cvm_send_packet () \n "); if (out_swp) { cvm_send_packet (); } printf("after cvm_send_packet () \n "); */ uint64_t app_timeout = cvmx_get_cycle (); #endif /* start the main loop */ while (1) { #ifdef DUTY_CYCLE end_cycle = cvmx_get_cycle(); /* check the wrap around case */ if (end_cycle < start_cycle) end_cycle += cpu_clock_hz; if ((end_cycle - start_cycle) > cvm_debug_print_interval) { inic_do_per_second_duty_cycle_processing(); } #endif /* DUTY_CYCLE */ cvmx_pow_work_request_async_nocheck(CVMX_SCR_WORK, 1); /* update the ticks variable */ while (cvmx_get_cycle() - tick_cycle > tick_step) { tick_cycle += tick_step; cvm_tcp_ticks++; if (!(cvm_tcp_ticks & 0x1f)) CVM_COMMON_HISTORY_SET_CYCLE(); } /* do common idle processing */ if ( (cvm_tcp_ticks - idle_processing_last_ticks) > idle_processing_interval_ticks) { if (cvmx_coremask_first_core(coremask_data)) { cvm_common_do_idle_processing(); } idle_processing_last_ticks = cvm_tcp_ticks; } #ifdef CVM_CLI_APP idle_cycle_start_value = cvmx_get_cycle(); #endif /* get work entry */ swp = (cvm_common_wqe_t *)cvmx_pow_work_response_async(CVMX_SCR_WORK); if (swp == NULL) { idle_counter++; if(core_id == highest_core_id) { cvm_enet_check_link_status(); } #ifdef CVM_CLI_APP cvmx_fau_atomic_add64(core_idle_cycles[core_id], (cvmx_get_cycle()-idle_cycle_start_value) ); #endif continue; } CVM_COMMON_EXTRA_STATS_ADD64 (CVM_FAU_REG_WQE_RCVD, 1); #ifdef WORK_QUEUE_ENTRY_SIZE_128 // { CVMX_PREFETCH0(swp); #else /* Prefetch work-queue entry */ CVMX_PREFETCH0(swp); CVMX_PREFETCH128(swp); #endif // WORK_QUEUE_ENTRY_SIZE_128 } out_swp = 0; out_swp_tail = 0; #ifdef DUTY_CYCLE /* we are about to start processing the packet - remember the cycle count */ process_start_cycle = cvmx_get_cycle(); #endif /* Short cut the common case */ if (cvmx_likely(swp->hw_wqe.unused == 0)) { goto packet_from_the_wire; } printf("Get work with unused is %X\n", swp->hw_wqe.unused); { { packet_from_the_wire: #if CVM_PKO_DONTFREE swp->hw_wqe.packet_ptr.s.i = 0; #endif #ifdef SANITY_CHECKS /* we have a work queue entry - do input sanity checks */ ret = cvm_common_input_sanity_and_buffer_count_update(swp); #endif if (cvmx_unlikely(swp->hw_wqe.word2.s.rcv_error)) { goto discard_swp; /* Receive error */ } #ifndef WORK_QUEUE_ENTRY_SIZE_128 // { { /* Make sure pre-fetch completed */ uint64_t dp = *(volatile uint64_t*)&swp->next; } #endif // WORK_QUEUE_ENTRY_SIZE_128 } { /* Initialize SW portion of the work-queue entry */ uint64_t *dptr = (uint64_t*)(&swp->next); dptr[0] = 0; dptr[1] = 0; dptr[2] = 0; dptr[3] = 0; } if(cvmx_unlikely(swp->hw_wqe.word2.s.not_IP)) { goto output; } /* Shortcut classification to avoid multiple lookups */ if( #ifndef INET6 swp->hw_wqe.word2.s.is_v6 || #endif swp->hw_wqe.word2.s.is_bcast #ifndef INET6 || swp->hw_wqe.word2.s.is_mcast #endif ) { goto discard_swp; /* Receive error */ } /* Packet is unicast IPv4, without L2 errors */ /* (All IP exceptions are dropped. This currently includes * IPv4 options and IPv6 extension headers.) */ if(cvmx_unlikely(swp->hw_wqe.word2.s.IP_exc)) { goto discard_swp; } /* Packet is Ipv4 (and no IP exceptions) */ if (cvmx_unlikely(swp->hw_wqe.word2.s.is_frag || !swp->hw_wqe.word2.s.tcp_or_udp)) { goto output; } #ifdef ANVL_RFC_793_COMPLIANCE /* RFC 793 says that: - We should send a RST out when we get a packet with FIN set without the ACK bit set in the flags field. - We should send a RST out when we get a packet with no flag set. Hence, let TCP stack handle these conditions. */ if (cvmx_unlikely(swp->hw_wqe.word2.s.L4_error && (cvmx_pip_l4_err_t)(swp->hw_wqe.word2.s.err_code != CVMX_PIP_TCP_FLG8_ERR) && (cvmx_pip_l4_err_t)(swp->hw_wqe.word2.s.err_code != CVMX_PIP_TCP_FLG9_ERR))) #else if (cvmx_unlikely(swp->hw_wqe.word2.s.L4_error)) #endif { cvm_tcp_handle_error(swp); goto discard_swp; } /* Packet is not fragmented, TCP/UDP, no IP exceptions/L4 errors */ /* We can try an L4 lookup now, but we need all the information */ ih = ((cvm_ip_ip_t *)&(swp->hw_wqe.packet_data[CVM_COMMON_PD_ALIGN])); if (!swp->hw_wqe.word2.s.is_v6) { /* for IPv4, we must subtract CVM_COMMON_PD_ALIGN rom tcp_offset to get the offset in the mbuf */ swp->l4_offset = ((uint16_t)(ih->ip_hl) << 2) + CVM_COMMON_PD_ALIGN; swp->l4_prot = ih->ip_p; } #ifdef INET6 else { ip6 = (struct cvm_ip6_ip6_hdr *) &swp->hw_wqe.packet_data[CVM_COMMON_IP6_PD_ALIGN]; CVM_COMMON_DBG_MSG (CVM_COMMON_DBG_LVL_5, "%s: %d Packet trace Src: %s/%d Dest: %s/%d prot: %d len: %d\n", __FUNCTION__, __LINE__, cvm_ip6_ip6_sprintf (&ip6->ip6_dst), conn.ie_fport, cvm_ip6_ip6_sprintf (&ip6->ip6_src), conn.ie_lport, swp->l4_prot, swp->hw_wqe.len); /* for IPv4, we must subtract CVM_COMMON_PD_ALIGN rom tcp_offset to get the offset in the mbuf */ swp->l4_offset = CVM_IP6_IP6_HDRLEN; swp->l4_prot = ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt; } #endif th = ((cvm_tcp_tcphdr_t *)&(swp->hw_wqe.packet_data[swp->l4_offset])); /* check if it is a TCP packet */ if (swp->l4_prot == CVM_IP_IPPROTO_TCP) { process_handle(swp); #ifdef INET6 if (!swp->hw_wqe.word2.s.is_v6) #endif { CVM_TCP_TCP_DUMP ((void*)ih); /* assume IPv4 for now */ conn.ie_laddr = ih->ip_dst.s_addr; conn.ie_faddr = ih->ip_src.s_addr; conn.ie_lport = th->th_dport; conn.ie_fport = th->th_sport; } #ifdef INET6 else { /* assume IPv4 for now */ memcpy (&conn.ie6_laddr, &ip6->ip6_dst, sizeof (struct cvm_ip6_in6_addr)); memcpy (&conn.ie6_faddr, &ip6->ip6_src, sizeof (struct cvm_ip6_in6_addr)); conn.ie_lport = th->th_dport; conn.ie_fport = th->th_sport; /* do a TCP lookup */ swp->tcb = cvm_tcp6_lookup (swp); CVM_COMMON_DBG_MSG (CVM_COMMON_DBG_LVL_5, "%s: %d TCPv6 lookup Src: %s/%d Dest: %s/%d ret_tcb: 0x%llx\n", __FUNCTION__, __LINE__, cvm_ip6_ip6_sprintf ((cvm_ip6_in6_addr_t *) &conn.ie6_faddr), conn.ie_fport, cvm_ip6_ip6_sprintf ((cvm_ip6_in6_addr_t *) &conn.ie6_laddr), conn.ie_lport, CAST64(swp->tcb)); } #endif // INET6 } goto output; } /* packet from wire */ } /* switch */ output: CVMX_SYNCWS; /* Send packet out */ if (out_swp) { cvm_send_packet(); } if(swp != NULL) { S3_send_packet((cvmx_wqe_t *)swp); swp = NULL; } #ifdef DUTY_CYCLE process_end_cycle = cvmx_get_cycle(); process_count += (process_end_cycle - process_start_cycle); #endif } return (0); discard_swp: /* Free the chained buffers */ cvm_common_packet_free(swp); /* Free the work queue entry */ cvm_common_free_fpa_buffer(swp, CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE / CVMX_CACHE_LINE_SIZE); swp = NULL; goto output; } /* inic_data_loop */