int NaClMachThreadIsInUntrusted(mach_port_t thread_port) {
  x86_thread_state_t state;
  thread_state_t statep = (thread_state_t) &state;
  mach_msg_type_number_t size = x86_THREAD_STATE_COUNT;
  kern_return_t kr;
  uint32_t nacl_thread_index;

  kr = thread_get_state(thread_port, x86_THREAD_STATE, statep, &size);
  if (kr != KERN_SUCCESS) {
    NaClLog(LOG_FATAL, "NaClMachThreadIsInUntrusted: "
            "thread_get_state() failed with error %i\n", kr);
  }
  CHECK(kr == KERN_SUCCESS);

#if NACL_BUILD_SUBARCH == 32
  CHECK(state.tsh.flavor == x86_THREAD_STATE32);
  nacl_thread_index = state.uts.ts32.__gs >> 3;
#elif NACL_BUILD_SUBARCH == 64
  nacl_thread_index = NaClGetThreadIndexForMachThread(thread_port);

  /*
   * If the thread isn't known to Native Client, it's not untrusted (at least
   * not by Native Client.)
   */
  if (nacl_thread_index == NACL_TLS_INDEX_INVALID) {
    return 0;
  }
#endif

  return NaClMachThreadStateIsInUntrusted(&state, nacl_thread_index);
}
void NaClSetCurrentMachThreadForThreadIndex(uint32_t nacl_thread_index) {
  /*
   * This implementation relies on the Mach port for the thread stored by the
   * pthread library, and assumes that the pthread library does not close and
   * re-acquire the Mach port for the thread. If that happens, Mach could
   * theoretically assign the port a different number in the process' port
   * table. This approach avoids having to deal with ownership of the port and
   * the system call overhad to obtain and deallocate it as would be the case
   * with mach_thread_self().
   *
   * When used by the Mach exception handler, this also assumes that the
   * thread port number when received for an exception will match the port
   * stored in the mach_threads table. This is guaranteed by how the kernel
   * coalesces ports in a single port namespace. (A task, or process, is a
   * single port namespace.)
   *
   * An alternative implementation that works on Mac OS X 10.6 or higher is to
   * use pthread_threadid_np() to obtain a thread ID to use as the key for
   * this thread map. Such thread IDs are unique system-wide. An exception
   * handler can find the thread ID for a Mach thread by calling thread_info()
   * with flavor THREAD_IDENTIFIER_INFO. This approach is not used here
   * because of the added system call overhead at exception time.
   */
  mach_port_t mach_thread = pthread_mach_thread_np(pthread_self());
  CHECK(mach_thread != MACH_PORT_NULL);

  DCHECK(nacl_thread_index > NACL_TLS_INDEX_INVALID &&
         nacl_thread_index < NACL_THREAD_MAX);
  DCHECK(mach_threads[nacl_thread_index] == MACH_PORT_NULL);
  DCHECK(NaClGetThreadIndexForMachThread(mach_thread) ==
         NACL_TLS_INDEX_INVALID);

  mach_threads[nacl_thread_index] = mach_thread;
}
void NaClClearMachThreadForThreadIndex(uint32_t nacl_thread_index) {
  mach_port_t mach_thread = mach_threads[nacl_thread_index];

  DCHECK(nacl_thread_index > NACL_TLS_INDEX_INVALID &&
         nacl_thread_index < NACL_THREAD_MAX);
  DCHECK(mach_thread == pthread_mach_thread_np(pthread_self()));

  mach_threads[nacl_thread_index] = MACH_PORT_NULL;

  DCHECK(NaClGetThreadIndexForMachThread(mach_thread) ==
         NACL_TLS_INDEX_INVALID);
}