Beispiel #1
0
int socket::connect_sock(const std::string& host, uint16_t port)
{
  int sock;
  NO_INTR(sock, ::socket(PF_INET, SOCK_STREAM, 0));
  if (FAILED(sock)){
    return -1;
  }

  int res;

  std::vector<ipv4_address> ips = resolve(host, port);
  for (int i=0; i < (int)ips.size(); i++){
    sockaddr_in addrin={};
    addrin.sin_family = PF_INET;
    addrin.sin_addr.s_addr = inet_addr(ips[i].to_string().c_str());
    addrin.sin_port = htons(port);

    NO_INTR(res,::connect(sock,(sockaddr*)&addrin,sizeof(addrin)));
    if (SUCCEEDED(res)) {
      return sock;
    }
  }

  NO_INTR(res, ::close(sock));
  return -1;
}
Beispiel #2
0
bool socket::set_nodelay_sock(int sock, bool on)
{
  if(sock < 0) { return false; }
#ifdef __linux__
  int n=on?1:0;
  int res;
  NO_INTR(res,setsockopt(sock,SOL_TCP,TCP_NODELAY,&n,sizeof(n)));
  if (FAILED(res)) return false;
  NO_INTR(res,setsockopt(sock,SOL_SOCKET,TCP_DEFER_ACCEPT,&n,sizeof(n)));
  return SUCCEEDED(res);
#else
  return true;
#endif
}
bool KPtyDevicePrivate::_k_canWrite()
{
    Q_Q(KPtyDevice);

    writeNotifier->setEnabled(false);
    if (writeBuffer.isEmpty())
        return false;

    qt_ignore_sigpipe();
    int wroteBytes;
    NO_INTR(wroteBytes,
            write(q->masterFd(),
                  writeBuffer.readPointer(), writeBuffer.readSize()));
    if (wroteBytes < 0) {
        q->setErrorString(QLatin1String("Error writing to PTY"));
        return false;
    }
    writeBuffer.free(wroteBytes);

    if (!emittedBytesWritten) {
        emittedBytesWritten = true;
        emit q->bytesWritten(wroteBytes);
        emittedBytesWritten = false;
    }

    if (!writeBuffer.isEmpty())
        writeNotifier->setEnabled(true);
    return true;
}
Beispiel #4
0
static int
safe_read (int fd, gchar *buffer, gint count, GError **error)
{
	int res;

	NO_INTR (res, read (fd, buffer, count));
	set_error_cond (res == -1, "%s", "Error reading from pipe.");
	return res;
}
Beispiel #5
0
int mmapper::open(const string& filename){
  int r;
  close();

  NO_INTR(fd, ::open(filename.c_str(), O_RDWR));
  if (FAILED(fd)) return -1;

  struct stat st_buf;
  NO_INTR(r, fstat(fd, &st_buf));
  if (FAILED(fd)) { close(); return -1; }
  length = st_buf.st_size;

  int prot = PROT_WRITE | PROT_READ;
  void *p = NULL;
  NO_INTR(p, mmap(NULL, length, prot, MAP_SHARED, fd, 0));
  if (p == MAP_FAILED) { close(); return -1; }
  ptr = (char*)p;

  return 0;
}
Beispiel #6
0
int socket::listen_sock(uint16_t port, int backlog)
{
  int res;
  int sock;

  NO_INTR(sock, ::socket(PF_INET, SOCK_STREAM, 0));
  if (FAILED(sock)) {
    return -1;
  }

  int yes = 1;
  NO_INTR(res, ::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
        (const char*)&yes, sizeof(yes)));

  if (FAILED(res)){
    NO_INTR(res, ::close(sock));
    return -1;
  }

  sockaddr_in saddr = {};
  saddr.sin_family = PF_INET;
  saddr.sin_addr.s_addr = htonl(INADDR_ANY);
  saddr.sin_port = htons(port);

  NO_INTR(res, ::bind(sock, (sockaddr*)&saddr, sizeof(saddr)));
  if (FAILED(res)){
    NO_INTR(res, ::close(sock));
    return -1;
  }

  linger ling={0,0};
  NO_INTR(res, ::setsockopt(sock, SOL_SOCKET, SO_LINGER,
        &ling, sizeof(ling)));
  if (FAILED(res)){
    NO_INTR(res, ::close(sock));
    return -1;
  }

  NO_INTR(res, ::listen(sock, backlog));
  if (FAILED(res)){
    NO_INTR(res, ::close(sock));
    return -1;
  }

  return sock;
}
Beispiel #7
0
bool socket::set_timeout_sockopt(int sock, int optname, double sec)
{
  if(sock < 0) { return false; }

  timeval tv;
  tv.tv_sec = std::max(0,(int)sec);
  tv.tv_usec = std::min(999999, std::max(0,(int)((sec-tv.tv_sec)*1e6)));

  int res;
  NO_INTR(res,setsockopt(sock,SOL_SOCKET,optname,&tv,sizeof(tv)));
  return SUCCEEDED(res);
}
_END_GOOGLE_NAMESPACE_

#if defined(__ELF__)

#include <dlfcn.h>
#include <elf.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <link.h>  // For ElfW() macro.
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include "symbolize.h"
#include "gconfig.h"

// Re-runs fn until it doesn't cause EINTR.
#define NO_INTR(fn)   do {} while ((fn) < 0 && errno == EINTR)

_START_GOOGLE_NAMESPACE_

// Read up to "count" bytes from file descriptor "fd" into the buffer
// starting at "buf" while handling short reads and EINTR.  On
// success, return the number of bytes read.  Otherwise, return -1.
static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) {
  SAFE_ASSERT(fd >= 0);
  SAFE_ASSERT(count <= SSIZE_MAX);
  char *buf0 = reinterpret_cast<char *>(buf);
  size_t num_bytes = 0;
  while (num_bytes < count) {
    ssize_t len;
    NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes));
    if (len < 0) {  // There was an error other than EINTR.
      return -1;
    }
    if (len == 0) {  // Reached EOF.
      break;
    }
    num_bytes += len;
  }
  SAFE_ASSERT(num_bytes <= count);
  return num_bytes;
}
/* Signal handler to help us recover from dying while we are attached to
 * other threads.
 */
static void SignalHandler(int signum, siginfo_t *si, void *data) {
  if (sig_pids != NULL) {
    if (signum == SIGABRT) {
      while (sig_num_threads-- > 0) {
        /* Not sure if sched_yield is really necessary here, but it does not */
        /* hurt, and it might be necessary for the same reasons that we have */
        /* to do so in sys_ptrace_detach().                                  */
        sys_sched_yield();
        sys_ptrace(PTRACE_KILL, sig_pids[sig_num_threads], 0, 0);
      }
    } else if (sig_num_threads > 0) {
      ResumeAllProcessThreads(sig_num_threads, (int *)sig_pids);
    }
  }
  sig_pids = NULL;
  if (sig_marker >= 0)
    NO_INTR(sys_close(sig_marker));
  sig_marker = -1;
  if (sig_proc >= 0)
    NO_INTR(sys_close(sig_proc));
  sig_proc = -1;

  sys__exit(signum == SIGABRT ? 1 : 2);
}
Beispiel #10
0
/*
 * This is the only use we have in mono/metadata
!g_spawn_async_with_pipes (NULL, (char**)addr_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &child_pid, &ch_in, &ch_out, NULL, NULL)
*/
gboolean
g_spawn_async_with_pipes (const gchar *working_directory,
			gchar **argv,
			gchar **envp,
			GSpawnFlags flags,
			GSpawnChildSetupFunc child_setup,
			gpointer user_data,
			GPid *child_pid,
			gint *standard_input,
			gint *standard_output,
			gint *standard_error,
			GError **error)
{
#ifdef G_OS_WIN32
#else
	pid_t pid;
	int info_pipe [2];
	int in_pipe [2] = { -1, -1 };
	int out_pipe [2] = { -1, -1 };
	int err_pipe [2] = { -1, -1 };
	int status;

	g_return_val_if_fail (argv != NULL, FALSE); /* Only mandatory arg */

	if (!create_pipe (info_pipe, error))
		return FALSE;

	if (standard_output && !create_pipe (out_pipe, error)) {
		CLOSE_PIPE (info_pipe);
		return FALSE;
	}

	if (standard_error && !create_pipe (err_pipe, error)) {
		CLOSE_PIPE (info_pipe);
		CLOSE_PIPE (out_pipe);
		return FALSE;
	}

	if (standard_input && !create_pipe (in_pipe, error)) {
		CLOSE_PIPE (info_pipe);
		CLOSE_PIPE (out_pipe);
		CLOSE_PIPE (err_pipe);
		return FALSE;
	}

	pid = fork ();
	if (pid == -1) {
		CLOSE_PIPE (info_pipe);
		CLOSE_PIPE (out_pipe);
		CLOSE_PIPE (err_pipe);
		CLOSE_PIPE (in_pipe);
		set_error ("%s", "Error in fork ()");
		return FALSE;
	}

	if (pid == 0) {
		/* No zombie left behind */
		if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
			pid = fork ();
		}

		if (pid != 0) {
			exit (pid == -1 ? 1 : 0);
		}  else {
			gint i;
			int fd;
			gchar *arg0;
			gchar **actual_args;
			gint unused;

			close (info_pipe [0]);
			close (in_pipe [1]);
			close (out_pipe [0]);
			close (err_pipe [0]);

			/* when exec* succeeds, we want to close this fd, which will return
			 * a 0 read on the parent. We're not supposed to keep it open forever.
			 * If exec fails, we still can write the error to it before closing.
			 */
			fcntl (info_pipe [1], F_SETFD, FD_CLOEXEC);

			if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
				pid = getpid ();
				NO_INTR (unused, write_all (info_pipe [1], &pid, sizeof (pid_t)));
			}

			if (working_directory && chdir (working_directory) == -1) {
				int err = errno;
				NO_INTR (unused, write_all (info_pipe [1], &err, sizeof (int)));
				exit (0);
			}

			if (standard_output) {
				dup2 (out_pipe [1], STDOUT_FILENO);
			} else if ((flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0) {
				fd = open ("/dev/null", O_WRONLY);
				dup2 (fd, STDOUT_FILENO);
			}

			if (standard_error) {
				dup2 (err_pipe [1], STDERR_FILENO);
			} else if ((flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0) {
				fd = open ("/dev/null", O_WRONLY);
				dup2 (fd, STDERR_FILENO);
			}

			if (standard_input) {
				dup2 (in_pipe [0], STDIN_FILENO);
			} else if ((flags & G_SPAWN_CHILD_INHERITS_STDIN) == 0) {
				fd = open ("/dev/null", O_RDONLY);
				dup2 (fd, STDIN_FILENO);
			}

			if ((flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN) != 0) {
				for (i = getdtablesize () - 1; i >= 3; i--)
					close (i);
			}

			actual_args = ((flags & G_SPAWN_FILE_AND_ARGV_ZERO) == 0) ? argv : argv + 1;
			if (envp == NULL)
				envp = environ;

			if (child_setup)
				child_setup (user_data);

			arg0 = argv [0];
			if (!g_path_is_absolute (arg0) || (flags & G_SPAWN_SEARCH_PATH) != 0) {
				arg0 = g_find_program_in_path (argv [0]);
				if (arg0 == NULL) {
					int err = ENOENT;
					write_all (info_pipe [1], &err, sizeof (int));
					exit (0);
				}
			}

			execve (arg0, actual_args, envp);
			write_all (info_pipe [1], &errno, sizeof (int));
			exit (0);
		}
	} else if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
		int w;
		/* Wait for the first child if two are created */
		NO_INTR (w, waitpid (pid, &status, 0));
		if (status == 1 || w == -1) {
			CLOSE_PIPE (info_pipe);
			CLOSE_PIPE (out_pipe);
			CLOSE_PIPE (err_pipe);
			CLOSE_PIPE (in_pipe);
			set_error ("Error in fork (): %d", status);
			return FALSE;
		}
	}
	close (info_pipe [1]);
	close (in_pipe [0]);
	close (out_pipe [1]);
	close (err_pipe [1]);

	if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0) {
		int x;
		NO_INTR (x, read (info_pipe [0], &pid, sizeof (pid_t))); /* if we read < sizeof (pid_t)... */
	}

	if (child_pid) {
		*child_pid = pid;
	}

	if (read (info_pipe [0], &status, sizeof (int)) != 0) {
		close (info_pipe [0]);
		close (in_pipe [0]);
		close (out_pipe [1]);
		close (err_pipe [1]);
		set_error_status (status, "Error in exec (%d -> %s)", status, strerror (status));
		return FALSE;
	}

	close (info_pipe [0]);
	if (standard_input)
		*standard_input = in_pipe [1];
	if (standard_output)
		*standard_output = out_pipe [0];
	if (standard_error)
		*standard_error = err_pipe [0];
#endif
	return TRUE;
}
Beispiel #11
0
gboolean
g_spawn_command_line_sync (const gchar *command_line,
				gchar **standard_output,
				gchar **standard_error,
				gint *exit_status,
				GError **error)
{
#ifdef G_OS_WIN32
#else
	pid_t pid;
	gchar **argv;
	gint argc;
	int stdout_pipe [2] = { -1, -1 };
	int stderr_pipe [2] = { -1, -1 };
	int status;
	int res;
	
	if (!g_shell_parse_argv (command_line, &argc, &argv, error))
		return FALSE;

	if (standard_output && !create_pipe (stdout_pipe, error))
		return FALSE;

	if (standard_error && !create_pipe (stderr_pipe, error)) {
		if (standard_output) {
			CLOSE_PIPE (stdout_pipe);
		}
		return FALSE;
	}

	pid = fork ();
	if (pid == 0) {
		gint i;

		if (standard_output) {
			close (stdout_pipe [0]);
			dup2 (stdout_pipe [1], STDOUT_FILENO);
		}

		if (standard_error) {
			close (stderr_pipe [0]);
			dup2 (stderr_pipe [1], STDERR_FILENO);
		}
		for (i = getdtablesize () - 1; i >= 3; i--)
			close (i);

		/* G_SPAWN_SEARCH_PATH is always enabled for g_spawn_command_line_sync */
		if (!g_path_is_absolute (argv [0])) {
			gchar *arg0;

			arg0 = g_find_program_in_path (argv [0]);
			if (arg0 == NULL) {
				exit (1);
			}
			//g_free (argv [0]);
			argv [0] = arg0;
		}
		execv (argv [0], argv);
		exit (1); /* TODO: What now? */
	}

	g_strfreev (argv);
	if (standard_output)
		close (stdout_pipe [1]);

	if (standard_error)
		close (stderr_pipe [1]);

	if (standard_output || standard_error) {
		res = read_pipes (stdout_pipe [0], standard_output, stderr_pipe [0], standard_error, error);
		if (res) {
			waitpid (pid, &status, WNOHANG); /* avoid zombie */
			return FALSE;
		}
	}

	NO_INTR (res, waitpid (pid, &status, 0));

	/* TODO: What if error? */
	if (WIFEXITED (status) && exit_status) {
		*exit_status = WEXITSTATUS (status);
	}
#endif
	return TRUE;
}
static void ListerThread(struct ListerParams *args) {
  int                found_parent = 0;
  pid_t              clone_pid  = sys_gettid(), ppid = sys_getppid();
  char               proc_self_task[80], marker_name[48], *marker_path;
  const char         *proc_paths[3];
  const char *const  *proc_path = proc_paths;
  int                proc = -1, marker = -1, num_threads = 0;
  int                max_threads = 0, sig;
  struct kernel_stat marker_sb, proc_sb;
  stack_t            altstack;

  /* Create "marker" that we can use to detect threads sharing the same
   * address space and the same file handles. By setting the FD_CLOEXEC flag
   * we minimize the risk of misidentifying child processes as threads;
   * and since there is still a race condition,  we will filter those out
   * later, anyway.
   */
  if ((marker = sys_socket(PF_LOCAL, SOCK_DGRAM, 0)) < 0 ||
      sys_fcntl(marker, F_SETFD, FD_CLOEXEC) < 0) {
  failure:
    args->result = -1;
    args->err    = errno;
    if (marker >= 0)
      NO_INTR(sys_close(marker));
    sig_marker = marker = -1;
    if (proc >= 0)
      NO_INTR(sys_close(proc));
    sig_proc = proc = -1;
    sys__exit(1);
  }

  /* Compute search paths for finding thread directories in /proc            */
  local_itoa(strrchr(strcpy(proc_self_task, "/proc/"), '\000'), ppid);
  strcpy(marker_name, proc_self_task);
  marker_path = marker_name + strlen(marker_name);
  strcat(proc_self_task, "/task/");
  proc_paths[0] = proc_self_task; /* /proc/$$/task/                          */
  proc_paths[1] = "/proc/";       /* /proc/                                  */
  proc_paths[2] = NULL;

  /* Compute path for marker socket in /proc                                 */
  local_itoa(strcpy(marker_path, "/fd/") + 4, marker);
  if (sys_stat(marker_name, &marker_sb) < 0) {
    goto failure;
  }

  /* Catch signals on an alternate pre-allocated stack. This way, we can
   * safely execute the signal handler even if we ran out of memory.
   */
  memset(&altstack, 0, sizeof(altstack));
  altstack.ss_sp    = args->altstack_mem;
  altstack.ss_flags = 0;
  altstack.ss_size  = ALT_STACKSIZE;
  sys_sigaltstack(&altstack, (const stack_t *)NULL);

  /* Some kernels forget to wake up traced processes, when the
   * tracer dies.  So, intercept synchronous signals and make sure
   * that we wake up our tracees before dying. It is the caller's
   * responsibility to ensure that asynchronous signals do not
   * interfere with this function.
   */
  sig_marker = marker;
  sig_proc   = -1;
  for (sig = 0; sig < sizeof(sync_signals)/sizeof(*sync_signals); sig++) {
    struct kernel_sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_sigaction_ = SignalHandler;
    sys_sigfillset(&sa.sa_mask);
    sa.sa_flags      = SA_ONSTACK|SA_SIGINFO|SA_RESETHAND;
    sys_sigaction(sync_signals[sig], &sa, (struct kernel_sigaction *)NULL);
  }
  
  /* Read process directories in /proc/...                                   */
  for (;;) {
    /* Some kernels know about threads, and hide them in "/proc"
     * (although they are still there, if you know the process
     * id). Threads are moved into a separate "task" directory. We
     * check there first, and then fall back on the older naming
     * convention if necessary.
     */
    if ((sig_proc = proc = c_open(*proc_path, O_RDONLY|O_DIRECTORY, 0)) < 0) {
      if (*++proc_path != NULL)
        continue;
      goto failure;
    }
    if (sys_fstat(proc, &proc_sb) < 0)
      goto failure;
    
    /* Since we are suspending threads, we cannot call any libc
     * functions that might acquire locks. Most notably, we cannot
     * call malloc(). So, we have to allocate memory on the stack,
     * instead. Since we do not know how much memory we need, we
     * make a best guess. And if we guessed incorrectly we retry on
     * a second iteration (by jumping to "detach_threads").
     *
     * Unless the number of threads is increasing very rapidly, we
     * should never need to do so, though, as our guestimate is very
     * conservative.
     */
    if (max_threads < proc_sb.st_nlink + 100)
      max_threads = proc_sb.st_nlink + 100;
    
    /* scope */ {
      pid_t pids[max_threads];
      int   added_entries = 0;
      sig_num_threads     = num_threads;
      sig_pids            = pids;
      for (;;) {
        struct kernel_dirent *entry;
        char buf[4096];
        ssize_t nbytes = sys_getdents(proc, (struct kernel_dirent *)buf,
                                      sizeof(buf));
        if (nbytes < 0)
          goto failure;
        else if (nbytes == 0) {
          if (added_entries) {
            /* Need to keep iterating over "/proc" in multiple
             * passes until we no longer find any more threads. This
             * algorithm eventually completes, when all threads have
             * been suspended.
             */
            added_entries = 0;
            sys_lseek(proc, 0, SEEK_SET);
            continue;
          }
          break;
        }
        for (entry = (struct kernel_dirent *)buf;
             entry < (struct kernel_dirent *)&buf[nbytes];
             entry = (struct kernel_dirent *)((char *)entry+entry->d_reclen)) {
          if (entry->d_ino != 0) {
            const char *ptr = entry->d_name;
            pid_t pid;
            
            /* Some kernels hide threads by preceding the pid with a '.'     */
            if (*ptr == '.')
              ptr++;
            
            /* If the directory is not numeric, it cannot be a
             * process/thread
             */
            if (*ptr < '0' || *ptr > '9')
              continue;
            pid = local_atoi(ptr);

            /* Attach (and suspend) all threads                              */
            if (pid && pid != clone_pid) {
              struct kernel_stat tmp_sb;
              char fname[entry->d_reclen + 48];
              strcat(strcat(strcpy(fname, "/proc/"),
                            entry->d_name), marker_path);
              
              /* Check if the marker is identical to the one we created      */
              if (sys_stat(fname, &tmp_sb) >= 0 &&
                  marker_sb.st_ino == tmp_sb.st_ino) {
                long i, j;

                /* Found one of our threads, make sure it is no duplicate    */
                for (i = 0; i < num_threads; i++) {
                  /* Linear search is slow, but should not matter much for
                   * the typically small number of threads.
                   */
                  if (pids[i] == pid) {
                    /* Found a duplicate; most likely on second pass         */
                    goto next_entry;
                  }
                }
                
                /* Check whether data structure needs growing                */
                if (num_threads >= max_threads) {
                  /* Back to square one, this time with more memory          */
                  NO_INTR(sys_close(proc));
                  goto detach_threads;
                }

                /* Attaching to thread suspends it                           */
                pids[num_threads++] = pid;
                sig_num_threads     = num_threads;
                if (sys_ptrace(PTRACE_ATTACH, pid, (void *)0,
                               (void *)0) < 0) {
                  /* If operation failed, ignore thread. Maybe it
                   * just died?  There might also be a race
                   * condition with a concurrent core dumper or
                   * with a debugger. In that case, we will just
                   * make a best effort, rather than failing
                   * entirely.
                   */
                  num_threads--;
                  sig_num_threads = num_threads;
                  goto next_entry;
                }
                while (sys_waitpid(pid, (int *)0, __WALL) < 0) {
                  if (errno != EINTR) {
                    sys_ptrace_detach(pid);
                    num_threads--;
                    sig_num_threads = num_threads;
                    goto next_entry;
                  }
                }
                
                if (sys_ptrace(PTRACE_PEEKDATA, pid, &i, &j) || i++ != j ||
                    sys_ptrace(PTRACE_PEEKDATA, pid, &i, &j) || i   != j) {
                  /* Address spaces are distinct, even though both
                   * processes show the "marker". This is probably
                   * a forked child process rather than a thread.
                   */
                  sys_ptrace_detach(pid);
                  num_threads--;
                  sig_num_threads = num_threads;
                } else {
                  found_parent |= pid == ppid;
                  added_entries++;
                }
              }
            }
          }
        next_entry:;
        }
      }
      NO_INTR(sys_close(proc));
      sig_proc = proc = -1;

      /* If we failed to find any threads, try looking somewhere else in
       * /proc. Maybe, threads are reported differently on this system.
       */
      if (num_threads > 1 || !*++proc_path) {
        NO_INTR(sys_close(marker));
        sig_marker = marker = -1;

        /* If we never found the parent process, something is very wrong.
         * Most likely, we are running in debugger. Any attempt to operate
         * on the threads would be very incomplete. Let's just report an
         * error to the caller.
         */
        if (!found_parent) {
          ResumeAllProcessThreads(num_threads, pids);
          sys__exit(3);
        }

        /* Now we are ready to call the callback,
         * which takes care of resuming the threads for us.
         */
        args->result = args->callback(args->parameter, num_threads,
                                      pids, args->ap);
        args->err = errno;

        /* Callback should have resumed threads, but better safe than sorry  */
        if (ResumeAllProcessThreads(num_threads, pids)) {
          /* Callback forgot to resume at least one thread, report error     */
          args->err    = EINVAL;
          args->result = -1;
        }

        sys__exit(0);
      }
    detach_threads:
      /* Resume all threads prior to retrying the operation                  */
      ResumeAllProcessThreads(num_threads, pids);
      sig_pids = NULL;
      num_threads = 0;
      sig_num_threads = num_threads;
      max_threads += 100;
    }
  }
}
/* Wrapper for open() which is guaranteed to never return EINTR.
 */
static int c_open(const char *fname, int flags, int mode) {
  ssize_t rc;
  NO_INTR(rc = sys_open(fname, flags, mode));
  return rc;
}
bool KPtyDevicePrivate::_k_canRead()
{
    Q_Q(KPtyDevice);
    qint64 readBytes = 0;

#ifdef Q_OS_IRIX // this should use a config define, but how to check it?
    size_t available;
#else
    int available;
#endif
    if (!::ioctl(q->masterFd(), PTY_BYTES_AVAILABLE, (char *) &available)) {
#ifdef Q_OS_SOLARIS
        // A Pty is a STREAMS module, and those can be activated
        // with 0 bytes available. This happens either when ^C is
        // pressed, or when an application does an explicit write(a,b,0)
        // which happens in experiments fairly often. When 0 bytes are
        // available, you must read those 0 bytes to clear the STREAMS
        // module, but we don't want to hit the !readBytes case further down.
        if (!available) {
            char c;
            // Read the 0-byte STREAMS message
            NO_INTR(readBytes, read(q->masterFd(), &c, 0));
            // Should return 0 bytes read; -1 is error
            if (readBytes < 0) {
                readNotifier->setEnabled(false);
                emit q->readEof();
                return false;
            }
            return true;
        }
#endif

        char *ptr = readBuffer.reserve(available);
#ifdef Q_OS_SOLARIS
        // Even if available > 0, it is possible for read()
        // to return 0 on Solaris, due to 0-byte writes in the stream.
        // Ignore them and keep reading until we hit *some* data.
        // In Solaris it is possible to have 15 bytes available
        // and to (say) get 0, 0, 6, 0 and 9 bytes in subsequent reads.
        // Because the stream is set to O_NONBLOCK in finishOpen(),
        // an EOF read will return -1.
        readBytes = 0;
        while (!readBytes)
#endif
        // Useless block braces except in Solaris
        {
          NO_INTR(readBytes, read(q->masterFd(), ptr, available));
        }
        if (readBytes < 0) {
            readBuffer.unreserve(available);
            q->setErrorString(QLatin1String("Error reading from PTY"));
            return false;
        }
        readBuffer.unreserve(available - readBytes); // *should* be a no-op
    }

    if (!readBytes) {
        readNotifier->setEnabled(false);
        emit q->readEof();
        return false;
    } else {
        if (!emittedReadyRead) {
            emittedReadyRead = true;
            emit q->readyRead();
            emittedReadyRead = false;
        }
        return true;
    }
}