libuv 학습 노트 (10)

22888 단어 학습 노트
libuv 학습 노트 (10)
uv_process_t 데이터 구조 와 관련 함수
데이터 구조
typedef struct uv_process_s uv_process_t;
struct uv_process_s {
  UV_HANDLE_FIELDS//uv_handle_t   ,      
  uv_exit_cb exit_cb;//    
  int pid;//  id
  //UV_PROCESS_PRIVATE_FIELDS   :
  struct uv_process_exit_s {                                                 
    UV_REQ_FIELDS//uv_req_t   ,      ,             
  } exit_req;                                                                 
  BYTE* child_stdio_buffer;//                                                                
  int exit_signal;//                                                                
  HANDLE wait_handle;//            ,   closehandle                                                         
  HANDLE process_handle;//                                                          
  volatile char exit_cb_pending;//               
};

프로 세 스 구성 체:
typedef struct uv_process_options_s {
  uv_exit_cb exit_cb; //        
  const char* file;//      utf8  

  //     utf8  。 args[0]       。windows     CreateProcess  ,  args  
  //      ,             ,  windows_verbatim_arguments
  char** args;
  //          utf8  
  char** env;
  //     utf8  
  const char* cwd;
  //  uv_spawn      
  unsigned int flags;
  //`stdio`      uv_stdio_container_t  ,uv_stdio_container_t           
  //       。    ,stdio[0]  stdin, fd 1 stdout, fd 2   stderr.
  // windows   ,        MSVCRT            2       
  int stdio_count;
  uv_stdio_container_t* stdio;
  //windows   
  uv_uid_t uid;
  uv_gid_t gid;
} uv_process_options_t;

상관 함수
1. 하위 프로 세 스 생 성.함수 내 보 내기, uv. h 에서 설명, process. c 에서 정의
초기 화, 내부 함수, uvspawn 에서 호출
static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
  uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS);
  handle->exit_cb = NULL;
  handle->pid = 0;
  handle->exit_signal = 0;
  handle->wait_handle = INVALID_HANDLE_VALUE;
  handle->process_handle = INVALID_HANDLE_VALUE;
  handle->child_stdio_buffer = NULL;
  handle->exit_cb_pending = 0;
  uv_req_init(loop, (uv_req_t*)&handle->exit_req);//     ,   UV_PROCESS_EXIT
  handle->exit_req.type = UV_PROCESS_EXIT;
  handle->exit_req.data = handle;
}

하위 프로 세 스 생 성
int uv_spawn(uv_loop_t* loop,
             uv_process_t* process,
             const uv_process_options_t* options) 
{
  int i;
  int err = 0;
  WCHAR* path = NULL, *alloc_path = NULL;
  BOOL result;
  WCHAR* application_path = NULL, *application = NULL, *arguments = NULL,
         *env = NULL, *cwd = NULL;
  STARTUPINFOW startup;
  PROCESS_INFORMATION info;
  DWORD process_flags;
  uv_process_init(loop, process);//   uv_process_t
  process->exit_cb = options->exit_cb;//          
  if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) {
    return UV_ENOTSUP;//windows   
  }
  if (options->file == NULL || options->args == NULL) {
    return UV_EINVAL;//                ,      
  }

  assert(options->file != NULL);
  assert(!(options->flags & ~(UV_PROCESS_DETACHED |
                              UV_PROCESS_SETGID |
                              UV_PROCESS_SETUID |
                              UV_PROCESS_WINDOWS_HIDE |
                              UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
  // utf8      utf16
  err = uv_utf8_to_utf16_alloc(options->file, &application);
  if (err)
    goto done;
  //       ,UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS          “”
  err = make_program_args(
      options->args,
      options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
      &arguments);
  if (err)
    goto done;
  //        
  if (options->env) {
     err = make_program_env(options->env, &env);
     if (err)
       goto done;
  }
  //        
  if (options->cwd) {
    /* Explicit cwd */
    err = uv_utf8_to_utf16_alloc(options->cwd, &cwd);
    if (err)
      goto done;

  } else {//      ,        
    /* Inherit cwd */
    DWORD cwd_len, r;

    cwd_len = GetCurrentDirectoryW(0, NULL);
    if (!cwd_len) {
      err = GetLastError();
      goto done;
    }

    cwd = (WCHAR*) uv__malloc(cwd_len * sizeof(WCHAR));
    if (cwd == NULL) {
      err = ERROR_OUTOFMEMORY;
      goto done;
    }

    r = GetCurrentDirectoryW(cwd_len, cwd);
    if (r == 0 || r >= cwd_len) {
      err = GetLastError();
      goto done;
    }
  }

  //        PATH
  path = find_path(env);
  if (path == NULL) {
    DWORD path_len, r;

    path_len = GetEnvironmentVariableW(L"PATH", NULL, 0);
    if (path_len == 0) {
      err = GetLastError();
      goto done;
    }

    alloc_path = (WCHAR*) uv__malloc(path_len * sizeof(WCHAR));
    if (alloc_path == NULL) {
      err = ERROR_OUTOFMEMORY;
      goto done;
    }
    path = alloc_path;

    r = GetEnvironmentVariableW(L"PATH", path, path_len);
    if (r == 0 || r >= path_len) {
      err = GetLastError();
      goto done;
    }
  }
  //  options  stdio    process->child_stdio_buffer
  //child_stdio_buffer    3 ,  255,  option   3 ,  child_stdio_buffer   
  //            UV_IGNORE(  )。  options->stdio   ,             
  //    
  err = uv__stdio_create(loop, options, &process->child_stdio_buffer);
  if (err)
    goto done;
  //     (            )
  application_path = search_path(application,
                                 cwd,
                                 path);
  if (application_path == NULL) {
    /* Not found. */
    err = ERROR_FILE_NOT_FOUND;
    goto done;
  }
  //  startup(STARTUPINFOW)   
  startup.cb = sizeof(startup);
  startup.lpReserved = NULL;
  startup.lpDesktop = NULL;
  startup.lpTitle = NULL;
  startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;

  startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer);
  startup.lpReserved2 = (BYTE*) process->child_stdio_buffer;
  //       (     )
  startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0);
  startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1);
  startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2);

  if (options->flags & UV_PROCESS_WINDOWS_HIDE) {
    /* Use SW_HIDE to avoid any potential process window. */
    startup.wShowWindow = SW_HIDE;
  } else {
    startup.wShowWindow = SW_SHOWDEFAULT;
  }

  process_flags = CREATE_UNICODE_ENVIRONMENT;

  if (options->flags & UV_PROCESS_DETACHED) {
    process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP;
  }
  //    
  if (!CreateProcessW(application_path,
                     arguments,
                     NULL,
                     NULL,
                     1,
                     process_flags,
                     env,
                     cwd,
                     &startup,
                     &info)) {
    /* CreateProcessW failed. */
    err = GetLastError();
    goto done;
  }
  //         id
  process->process_handle = info.hProcess;
  process->pid = info.dwProcessId;
  //           ,       job  ,               
  if (!(options->flags & UV_PROCESS_DETACHED)) {
    //uv__init_global_job_handle        ,      uv__init_global_job_handle
    uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle);
    //         
    if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) {
      DWORD err = GetLastError();
      if (err != ERROR_ACCESS_DENIED)
        uv_fatal_error(err, "AssignProcessToJobObject");
    }
  }
  //                 id
  for (i = 0; i < options->stdio_count; i++) {
    const uv_stdio_container_t* fdopt = &options->stdio[i];
    if (fdopt->flags & UV_CREATE_PIPE &&
        fdopt->data.stream->type == UV_NAMED_PIPE &&
        ((uv_pipe_t*) fdopt->data.stream)->ipc) {
      ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_pid = info.dwProcessId;
    }
  }
  //           ,     ,                
  result = RegisterWaitForSingleObject(&process->wait_handle,
      process->process_handle, exit_wait_callback, (void*)process, INFINITE,
      WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
  if (!result) {
    uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject");
  }
  //           
  CloseHandle(info.hThread);
  assert(!err);
  //  uv_process_t
  uv__handle_start(process);
  //    
 done:
  uv__free(application);
  uv__free(application_path);
  uv__free(arguments);
  uv__free(cwd);
  uv__free(env);
  uv__free(alloc_path);
  //                   
  if (process->child_stdio_buffer != NULL) {
    /* Clean up child stdio handles. */
    uv__stdio_destroy(process->child_stdio_buffer);
    process->child_stdio_buffer = NULL;
  }
  return uv_translate_sys_error(err);
}

하위 스 레 드 가 닫 힌 후 반전 함수 exitwait_callback, windows 스 레 드 탱크 에서 호출 됩 니 다.
static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) 
{
  uv_process_t* process = (uv_process_t*) data;
  uv_loop_t* loop = process->loop;

  assert(didTimeout == FALSE);
  assert(process);
  assert(!process->exit_cb_pending);

  process->exit_cb_pending = 1;

  // iocp    
  POST_COMPLETION_FOR_REQ(loop, &process->exit_req);
}

uv_run 에 서 는 스 레 드 종료 정 보 를 받 은 후 uv 를 호출 합 니 다.process_reqs 처리 요청, 최종 호출 uvprocess_proc_exit
void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) 
{
  int64_t exit_code;
  DWORD status;

  assert(handle->exit_cb_pending);
  handle->exit_cb_pending = 0;

  //  handle       ,    handle。                  uv_close  
  //handle
  /* callback now. */
  if (handle->flags & UV__HANDLE_CLOSING) {
    uv_want_endgame(loop, (uv_handle_t*) handle);
    return;
  }

  //    
  if (handle->wait_handle != INVALID_HANDLE_VALUE) {
    UnregisterWait(handle->wait_handle);
    handle->wait_handle = INVALID_HANDLE_VALUE;
  }
  //  handle
  uv__handle_stop(handle);

  if (GetExitCodeProcess(handle->process_handle, &status)) {
    exit_code = status;
  } else {
    /* Unable to to obtain the exit code. This should never happen. */
    exit_code = uv_translate_sys_error(GetLastError());
  }
  //    
  if (handle->exit_cb) {
    handle->exit_cb(handle, exit_code, handle->exit_signal);
  }
}

uv 통과 하기close 닫 기 uvprocess_t, 최종 호출 uvprocess_close
void uv_process_close(uv_loop_t* loop, uv_process_t* handle) 
{
  uv__handle_closing(handle);//    UV_HANDLE_CLOSING

  if (handle->wait_handle != INVALID_HANDLE_VALUE) {
    //    
    BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE);
    if (!r) {
      /* This should never happen, and if it happens, we can't recover... */
      uv_fatal_error(GetLastError(), "UnregisterWaitEx");
    }

    handle->wait_handle = INVALID_HANDLE_VALUE;
  }
  //           exit_wait_callback    ,    handle,      loop      
  //        handle
  if (!handle->exit_cb_pending) {
    uv_want_endgame(loop, (uv_handle_t*)handle);
  }
}

libuv 를 사용 하여 하위 프로 세 스 를 만 듭 니 다. 출력, 입력 방향 을 바 꾸 거나 이름 파 이 프 를 사용 하여 프로 세 스 간 통신 을 할 수 있 습 니 다. 이 부분 은 다음 uv 와 통신 할 수 있 습 니 다.pipe_t 및 uvstream_t 등 내용 관련.

좋은 웹페이지 즐겨찾기