Exemplo n.º 1
0
int
_gpgme_io_read ( int fd, void *buffer, size_t count )
{
    int nread;
    struct reader_context_s *c = find_reader (fd,1);

    DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int)count );
    if ( !c ) {
        DEBUG0 ( "no reader thread\n");
        return -1;
    }
    if (c->eof_shortcut) {
        DEBUG1 ("fd %d: EOF (again)", fd );
        return 0;
    }

    LOCK (c->mutex);
    if (c->readpos == c->writepos && !c->error) { /*no data avail*/
        UNLOCK (c->mutex);
        DEBUG2 ("fd %d: waiting for data from thread %p", fd, c->thread_hd);
        WaitForSingleObject (c->have_data_ev, INFINITE);
        DEBUG2 ("fd %d: data from thread %p available", fd, c->thread_hd);
        LOCK (c->mutex);
    }
    
    if (c->readpos == c->writepos || c->error) {
        UNLOCK (c->mutex);
        c->eof_shortcut = 1;
        if (c->eof) {
            DEBUG1 ("fd %d: EOF", fd );
            return 0;
        }
        if (!c->error) {
            DEBUG1 ("fd %d: EOF but eof flag not set", fd );
            return 0;
        }
        DEBUG1 ("fd %d: read error", fd );
        return -1;
    }
      
    nread = c->readpos < c->writepos? c->writepos - c->readpos
                                    : READBUF_SIZE - c->readpos;
    if (nread > count)
        nread = count;
    memcpy (buffer, c->buffer+c->readpos, nread);
    c->readpos = (c->readpos + nread) % READBUF_SIZE;
    if (c->readpos == c->writepos && !c->eof) {
        if ( !ResetEvent (c->have_data_ev) )
            DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ());
    }
    if (!SetEvent (c->have_space_ev))
        DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
    UNLOCK (c->mutex);

    DEBUG2 ("fd %d: got %d bytes\n", fd, nread );
    if (nread > 0)
      _gpgme_debug (2, "fd %d: got `%.*s'\n", fd, nread, buffer);

    return nread;
}
Exemplo n.º 2
0
/*
 * Select on the list of fds.
 * Returns: -1 = error
 *           0 = timeout or nothing to select
 *          >0 = number of signaled fds
 */
int
_gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds, int nonblock )
{
    HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
    int    waitidx[MAXIMUM_WAIT_OBJECTS];
    int code, nwait;
    int i, any;
    int count;
    void *dbg_help;

 restart:
    DEBUG_BEGIN (dbg_help, 3, "select on [ ");
    any = 0;
    nwait = 0;
    count = 0;
    for ( i=0; i < nfds; i++ ) {
        if ( fds[i].fd == -1 ) 
            continue;
        fds[i].signaled = 0;
        if ( fds[i].for_read || fds[i].for_write ) {
            if ( fds[i].frozen ) {
                DEBUG_ADD1 (dbg_help, "f%d ", fds[i].fd );
            }
            else if ( fds[i].for_read ) {
                struct reader_context_s *c = find_reader (fds[i].fd,1);
                
                if (!c) { 
                    DEBUG1 ("oops: no reader thread for fd %d", fds[i].fd);
                }
                else {
                    if ( nwait >= DIM (waitbuf) ) {
                        DEBUG_END (dbg_help, "oops ]");
                        DEBUG0 ("Too many objects for WFMO!" );
                        return -1;
                    }
                    waitidx[nwait]   = i;
                    waitbuf[nwait++] = c->have_data_ev;
                }
                DEBUG_ADD1 (dbg_help, "r%d ", fds[i].fd );
                any = 1;
            }
            else if ( fds[i].for_write ) {
                struct writer_context_s *c = find_writer (fds[i].fd,1);
                
                if (!c) { 
                    DEBUG1 ("oops: no writer thread for fd %d", fds[i].fd);
                }
                else {
                    if ( nwait >= DIM (waitbuf) ) {
                        DEBUG_END (dbg_help, "oops ]");
                        DEBUG0 ("Too many objects for WFMO!" );
                        return -1;
                    }
		    waitidx[nwait]   = i;
		    waitbuf[nwait++] = c->is_empty;
                }
		DEBUG_ADD1 (dbg_help, "w%d ", fds[i].fd );
		any = 1;
            }
        }
    }
    DEBUG_END (dbg_help, "]");
    if (!any) 
        return 0;

    code = WaitForMultipleObjects ( nwait, waitbuf, 0, nonblock ? 0 : 1000);
    if ( code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait ) {
        /* This WFMO is a really silly function:  It does return either
         * the index of the signaled object or if 2 objects have been
         * signalled at the same time, the index of the object with the
         * lowest object is returned - so and how do we find out
         * how many objects have been signaled???.
         * The only solution I can imagine is to test each object starting
         * with the returned index individually - how dull.
         */
        any = 0;
        for (i=code - WAIT_OBJECT_0; i < nwait; i++ ) {
            if (WaitForSingleObject (waitbuf[i], 0) == WAIT_OBJECT_0) {
                assert (waitidx[i] >=0 && waitidx[i] < nfds);
                fds[waitidx[i]].signaled = 1;
                any = 1;
                count++;
            }
        }
        if (!any) {
            DEBUG0 ("Oops: No signaled objects found after WFMO");
            count = -1;
        }
    }
    else if ( code == WAIT_TIMEOUT ) {
        DEBUG0 ("WFMO timed out\n" );
    }  
    else if (code == WAIT_FAILED ) {
        int le = (int)GetLastError ();
        if ( le == ERROR_INVALID_HANDLE ) {
            int k, j = handle_to_fd (waitbuf[i]);
                    
            DEBUG1 ("WFMO invalid handle %d removed\n", j);
            for (k=0 ; k < nfds; k++ ) {
                if ( fds[k].fd == j ) {
                    fds[k].for_read = fds[k].for_write = 0;
                    goto restart;
                }
            }
            DEBUG0 (" oops, or not???\n");
        }
        DEBUG1 ("WFMO failed: %d\n", le );
        count = -1;
    }
    else {
        DEBUG1 ("WFMO returned %d\n", code );
        count = -1;
    }

    if ( count ) {
        DEBUG_BEGIN (dbg_help, 3, " signaled [ ");
        for ( i=0; i < nfds; i++ ) {
            if ( fds[i].fd == -1 ) 
                continue;
            if ( (fds[i].for_read || fds[i].for_write) && fds[i].signaled ) {
                DEBUG_ADD2 (dbg_help, "%c%d ",
                            fds[i].for_read? 'r':'w',fds[i].fd );
            }
        }
        DEBUG_END (dbg_help, "]");
    }
    
    return count;
}
Exemplo n.º 3
0
int
_gpgme_io_pipe (int filedes[2], int inherit_idx)
{
  HANDLE rh;
  HANDLE wh;
  SECURITY_ATTRIBUTES sec_attr;
  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
	      "inherit_idx=%i (GPGME uses it for %s)",
	      inherit_idx, inherit_idx ? "reading" : "writing");

  memset (&sec_attr, 0, sizeof (sec_attr));
  sec_attr.nLength = sizeof (sec_attr);
  sec_attr.bInheritHandle = FALSE;
  
  if (!CreatePipe (&rh, &wh, &sec_attr, PIPEBUF_SIZE))
    {
      TRACE_LOG1 ("CreatePipe failed: ec=%d", (int) GetLastError ());
      /* FIXME: Should translate the error code.  */
      errno = EIO;
      return TRACE_SYSRES (-1);
    }

  /* Make one end inheritable.  */
  if (inherit_idx == 0)
    {
      struct writer_context_s *ctx;
      HANDLE hd;
      if (!DuplicateHandle (GetCurrentProcess(), rh,
			    GetCurrentProcess(), &hd, 0,
			    TRUE, DUPLICATE_SAME_ACCESS))
	{
	  TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
		      (int) GetLastError ());
	  CloseHandle (rh);
	  CloseHandle (wh);
	  /* FIXME: Should translate the error code.  */
	  errno = EIO;
	  return TRACE_SYSRES (-1);
        }
      CloseHandle (rh);
      rh = hd;

      ctx = find_writer (handle_to_fd (wh), 0);
      assert (ctx == NULL);
      ctx = find_writer (handle_to_fd (wh), 1);
      if (!ctx)
	{
	  CloseHandle (rh);
	  CloseHandle (wh);
	  /* FIXME: Should translate the error code.  */
	  errno = EIO;
	  return TRACE_SYSRES (-1);
	}
    }
  else if (inherit_idx == 1)
    {
      struct reader_context_s *ctx;
      HANDLE hd;
      if (!DuplicateHandle( GetCurrentProcess(), wh,
			    GetCurrentProcess(), &hd, 0,
			    TRUE, DUPLICATE_SAME_ACCESS))
	{
	  TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
		      (int) GetLastError ());
	  CloseHandle (rh);
	  CloseHandle (wh);
	  /* FIXME: Should translate the error code.  */
	  errno = EIO;
	  return TRACE_SYSRES (-1);
        }
      CloseHandle (wh);
      wh = hd;

      ctx = find_reader (handle_to_fd (rh), 0);
      assert (ctx == NULL);
      ctx = find_reader (handle_to_fd (rh), 1);
      if (!ctx)
	{
	  CloseHandle (rh);
	  CloseHandle (wh);
	  /* FIXME: Should translate the error code.  */
	  errno = EIO;
	  return TRACE_SYSRES (-1);
	}
    }
  
  filedes[0] = handle_to_fd (rh);
  filedes[1] = handle_to_fd (wh);
  return TRACE_SUC2 ("read=%p, write=%p", rh, wh);
}
Exemplo n.º 4
0
int
_gpgme_io_read (int fd, void *buffer, size_t count)
{
  int nread;
  struct reader_context_s *ctx;
  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
	      "buffer=%p, count=%u", buffer, count);
  
  ctx = find_reader (fd, 1);
  if (!ctx)
    {
      errno = EBADF;
      return TRACE_SYSRES (-1);
    }
  if (ctx->eof_shortcut)
    return TRACE_SYSRES (0);

  LOCK (ctx->mutex);
  if (ctx->readpos == ctx->writepos && !ctx->error)
    {
      /* No data available.  */
      UNLOCK (ctx->mutex);
      TRACE_LOG1 ("waiting for data from thread %p", ctx->thread_hd);
      WaitForSingleObject (ctx->have_data_ev, INFINITE);
      TRACE_LOG1 ("data from thread %p available", ctx->thread_hd);
      LOCK (ctx->mutex);
    }
  
  if (ctx->readpos == ctx->writepos || ctx->error)
    {
      UNLOCK (ctx->mutex);
      ctx->eof_shortcut = 1;
      if (ctx->eof)
	return TRACE_SYSRES (0);
      if (!ctx->error)
	{
	  TRACE_LOG ("EOF but ctx->eof flag not set");
	  return 0;
	}
      errno = ctx->error_code;
      return TRACE_SYSRES (-1);
    }
  
  nread = ctx->readpos < ctx->writepos
    ? ctx->writepos - ctx->readpos
    : READBUF_SIZE - ctx->readpos;
  if (nread > count)
    nread = count;
  memcpy (buffer, ctx->buffer + ctx->readpos, nread);
  ctx->readpos = (ctx->readpos + nread) % READBUF_SIZE;
  if (ctx->readpos == ctx->writepos && !ctx->eof)
    {
      if (!ResetEvent (ctx->have_data_ev))
	{
	  TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
	  UNLOCK (ctx->mutex);
	  /* FIXME: Should translate the error code.  */
	  errno = EIO;
	  return TRACE_SYSRES (-1);
	}
    }
  if (!SetEvent (ctx->have_space_ev))
    {
      TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d",
		  ctx->have_space_ev, (int) GetLastError ());
      UNLOCK (ctx->mutex);
      /* FIXME: Should translate the error code.  */
      errno = EIO;
      return TRACE_SYSRES (-1);
    }
  UNLOCK (ctx->mutex);
  
  TRACE_LOGBUF (buffer, nread);
  return TRACE_SYSRES (nread);
}
Exemplo n.º 5
0
int
_gpgme_io_dup (int fd)
{
  HANDLE handle = fd_to_handle (fd);
  HANDLE new_handle = fd_to_handle (fd);
  int i;
  struct reader_context_s *rd_ctx;
  struct writer_context_s *wt_ctx;

  TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd);

  if (!DuplicateHandle (GetCurrentProcess(), handle,
			GetCurrentProcess(), &new_handle,
			0, FALSE, DUPLICATE_SAME_ACCESS))
    {
      TRACE_LOG1 ("DuplicateHandle failed: ec=%d\n", (int) GetLastError ());
      /* FIXME: Translate error code.  */
      errno = EIO;
      return TRACE_SYSRES (-1);
    }

  rd_ctx = find_reader (fd, 0);
  if (rd_ctx)
    {
      /* No need for locking, as the only races are against the reader
	 thread itself, which doesn't touch refcount.  */
      rd_ctx->refcount++;

      LOCK (reader_table_lock);
      for (i = 0; i < reader_table_size; i++)
	if (!reader_table[i].used)
	  break;
      /* FIXME.  */
      assert (i != reader_table_size);
      reader_table[i].fd = handle_to_fd (new_handle);
      reader_table[i].context = rd_ctx;
      reader_table[i].used = 1;
      UNLOCK (reader_table_lock);
    }

  wt_ctx = find_writer (fd, 0);
  if (wt_ctx)
    {
      /* No need for locking, as the only races are against the writer
	 thread itself, which doesn't touch refcount.  */
      wt_ctx->refcount++;

      LOCK (writer_table_lock);
      for (i = 0; i < writer_table_size; i++)
	if (!writer_table[i].used)
	  break;
      /* FIXME.  */
      assert (i != writer_table_size);
      writer_table[i].fd = handle_to_fd (new_handle);
      writer_table[i].context = wt_ctx;
      writer_table[i].used = 1;
      UNLOCK (writer_table_lock);
    }

  return TRACE_SYSRES (handle_to_fd (new_handle));
}
Exemplo n.º 6
0
/* Select on the list of fds.  Returns: -1 = error, 0 = timeout or
   nothing to select, > 0 = number of signaled fds.  */
int
_gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
{
  HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
  int waitidx[MAXIMUM_WAIT_OBJECTS];
  int code;
  int nwait;
  int i;
  int any;
  int count;
  void *dbg_help;
  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
	      "nfds=%u, nonblock=%u", nfds, nonblock);

 restart:
  TRACE_SEQ (dbg_help, "select on [ ");
  any = 0;
  nwait = 0;
  count = 0;
  for (i=0; i < nfds; i++)
    {
      if (fds[i].fd == -1)
	continue;
      fds[i].signaled = 0;
      if (fds[i].for_read || fds[i].for_write)
	{
	  if (fds[i].for_read)
	    {
	      struct reader_context_s *ctx = find_reader (fds[i].fd,0);
	      
	      if (!ctx)
		TRACE_LOG1 ("error: no reader for FD 0x%x (ignored)",
			    fds[i].fd);
	      else
		{
		  if (nwait >= DIM (waitbuf))
		    {
		      TRACE_END (dbg_help, "oops ]");
		      TRACE_LOG ("Too many objects for WFMO!");
		      /* FIXME: Should translate the error code.  */
		      errno = EIO;
		      return TRACE_SYSRES (-1);
                    }
		  waitidx[nwait] = i;
		  waitbuf[nwait++] = ctx->have_data_ev;
                }
	      TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
	      any = 1;
            }
	  else if (fds[i].for_write)
	    {
	      struct writer_context_s *ctx = find_writer (fds[i].fd,0);
              
	      if (!ctx)
		TRACE_LOG1 ("error: no writer for FD 0x%x (ignored)",
			    fds[i].fd);
	      else
		{
		  if (nwait >= DIM (waitbuf))
		    {
		      TRACE_END (dbg_help, "oops ]");
		      TRACE_LOG ("Too many objects for WFMO!");
		      /* FIXME: Should translate the error code.  */
		      errno = EIO;
		      return TRACE_SYSRES (-1);
                    }
		  waitidx[nwait] = i;
		  waitbuf[nwait++] = ctx->is_empty;
                }
	      TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
	      any = 1;
            }
        }
    }
  TRACE_END (dbg_help, "]");
  if (!any) 
    return TRACE_SYSRES (0);

  code = WaitForMultipleObjects (nwait, waitbuf, 0, nonblock ? 0 : 1000);
  if (code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait)
    {
      /* This WFMO is a really silly function: It does return either
	 the index of the signaled object or if 2 objects have been
	 signalled at the same time, the index of the object with the
	 lowest object is returned - so and how do we find out how
	 many objects have been signaled???.  The only solution I can
	 imagine is to test each object starting with the returned
	 index individually - how dull.  */
      any = 0;
      for (i = code - WAIT_OBJECT_0; i < nwait; i++)
	{
	  if (WaitForSingleObject (waitbuf[i], 0) == WAIT_OBJECT_0)
	    {
	      assert (waitidx[i] >=0 && waitidx[i] < nfds);
	      fds[waitidx[i]].signaled = 1;
	      any = 1;
	      count++;
	    }
	}
      if (!any)
	{
	  TRACE_LOG ("no signaled objects found after WFMO");
	  count = -1;
	}
    }
  else if (code == WAIT_TIMEOUT)
    TRACE_LOG ("WFMO timed out");
  else if (code == WAIT_FAILED)
    {
      int le = (int) GetLastError ();
      if (le == ERROR_INVALID_HANDLE)
	{
	  int k;
	  int j = handle_to_fd (waitbuf[i]);
          
	  TRACE_LOG1 ("WFMO invalid handle %d removed", j);
	  for (k = 0 ; k < nfds; k++)
	    {
	      if (fds[k].fd == j)
		{
		  fds[k].for_read = fds[k].for_write = 0;
		  goto restart;
                }
            }
	  TRACE_LOG (" oops, or not???");
        }
      TRACE_LOG1 ("WFMO failed: %d", le);
      count = -1;
    }
  else
    {
      TRACE_LOG1 ("WFMO returned %d", code);
      count = -1;
    }
  
  if (count > 0)
    {
      TRACE_SEQ (dbg_help, "select OK [ ");
      for (i = 0; i < nfds; i++)
	{
	  if (fds[i].fd == -1)
	    continue;
	  if ((fds[i].for_read || fds[i].for_write) && fds[i].signaled)
	    TRACE_ADD2 (dbg_help, "%c0x%x ",
			fds[i].for_read ? 'r' : 'w', fds[i].fd);
        }
      TRACE_END (dbg_help, "]");
    }

  if (count < 0)
    {
      /* FIXME: Should determine a proper error code.  */
      errno = EIO;
    }
  
  return TRACE_SYSRES (count);
}
Exemplo n.º 7
0
int
__nisdb_rlock(__nisdb_rwlock_t *rw) {

	int		ret;
	pthread_t	myself = pthread_self();
	__nisdb_rl_t	*rr;

	if (rw == 0) {
#ifdef	NISDB_MT_DEBUG
		/* This shouldn't happen */
		abort();
#endif	/* NISDB_MT_DEBUG */
		return (EFAULT);
	}

	if (rw->destroyed != 0)
		return (ESHUTDOWN);

	if (rw->force_write)
		return (__nisdb_wlock(rw));

	if ((ret = mutex_lock(&rw->mutex)) != 0)
		return (ret);

	if (rw->destroyed != 0) {
		(void) mutex_unlock(&rw->mutex);
		return (ESHUTDOWN);
	}

	rr = find_reader(myself, rw);

	/* Wait for writer to complete; writer == myself also OK */
	while (rw->writer_count > 0 && rw->writer.id != myself) {
		if (rr != 0) {
			rr->wait = 1;
			rw->reader_blocked++;
		}
		if ((ret = cond_wait(&rw->cv, &rw->mutex)) != 0) {
			if (rr != 0) {
				rr->wait = 0;
				if (rw->reader_blocked > 0)
					rw->reader_blocked--;
#ifdef	NISDB_MT_DEBUG
				else
					abort();
#endif	/* NISDB_MT_DEBUG */
			}
			(void) mutex_unlock(&rw->mutex);
			return (ret);
		}
		if (rr != 0) {
			rr->wait = 0;
			if (rw->reader_blocked > 0)
				rw->reader_blocked--;
#ifdef	NISDB_MT_DEBUG
			else
				abort();
#endif	/* NISDB_MT_DEBUG */
		}
	}

	rr = increment_reader(myself, rw);
	ret = mutex_unlock(&rw->mutex);
	return ((rr == 0) ? ENOMEM : ret);
}
Exemplo n.º 8
0
int
__nisdb_wlock_trylock(__nisdb_rwlock_t *rw, int trylock) {

	int		ret;
	pthread_t	myself = pthread_self();
	int		all_readers_blocked = 0;
	__nisdb_rl_t	*rr = 0;

	if (rw == 0) {
#ifdef	NISDB_MT_DEBUG
		/* This shouldn't happen */
		abort();
#endif	/* NISDB_MT_DEBUG */
		return (EFAULT);
	}

	if (rw->destroyed != 0)
		return (ESHUTDOWN);

	if ((ret = mutex_lock(&rw->mutex)) != 0)
		return (ret);

	if (rw->destroyed != 0) {
		(void) mutex_unlock(&rw->mutex);
		return (ESHUTDOWN);
	}

	/* Simplest (and probably most common) case: no readers or writers */
	if (rw->reader_count == 0 && rw->writer_count == 0) {
		rw->writer_count = 1;
		rw->writer.id = myself;
		rw->writer.count = 1;
		return (mutex_unlock(&rw->mutex));
	}

	/*
	 * Need to know if we're holding a read lock already, and if
	 * all other readers are blocked waiting for the mutex.
	 */
	if (rw->reader_count > 0) {
		if ((rr = find_reader(myself, rw)) != 0) {
			if (rr->count)
				/*
				 * We're already holding a read lock, so
				 * if the number of readers equals the number
				 * of blocked readers plus one, all other
				 * readers are blocked.
				 */
				if (rw->reader_count ==
						(rw->reader_blocked + 1))
					all_readers_blocked = 1;
			else
				/*
				 * We're not holding a read lock, so the
				 * number of readers should equal the number
				 * of blocked readers if all readers are
				 * blocked.
				 */
				if (rw->reader_count == rw->reader_blocked)
					all_readers_blocked = 1;
		}
	}

	/* Wait for reader(s) or writer to finish */
	while (1) {
		/*
		 * We can stop looping if one of the following holds:
		 *	- No readers, no writers
		 *	- No writers (or writer is myself), and one of:
		 *		- No readers
		 *		- One reader, and it's us
		 *		- N readers, but all blocked on the mutex
		 */
		if (
			(rw->writer_count == 0 && rw->reader_count == 0) ||
			((rw->writer_count == 0 || rw->writer.id == myself) &&
				(rw->reader_count == 0) ||
				(rw->reader_count == 1 &&
					rw->reader.id == myself))) {
			break;
		}
		/*
		 * Provided that all readers are blocked on the mutex
		 * we break a potential dead-lock by acquiring the
		 * write lock.
		 */
		if (all_readers_blocked) {
			if (rw->writer_count == 0 || rw->writer.id == myself) {
				break;
			}
		}

		/*
		 * If 'trylock' is set, tell the caller that we'd have to
		 * block to obtain the lock.
		 */
		if (trylock) {
			(void) mutex_unlock(&rw->mutex);
			return (EBUSY);
		}

		/* If we're also a reader, indicate that we're blocking */
		if (rr != 0) {
			rr->wait = 1;
			rw->reader_blocked++;
		}
		if ((ret = cond_wait(&rw->cv, &rw->mutex)) != 0) {
			if (rr != 0) {
				rr->wait = 0;
				if (rw->reader_blocked > 0)
					rw->reader_blocked--;
#ifdef	NISDB_MT_DEBUG
				else
					abort();
#endif	/* NISDB_MT_DEBUG */
			}
			(void) mutex_unlock(&rw->mutex);
			return (ret);
		}
		if (rr != 0) {
			rr->wait = 0;
			if (rw->reader_blocked > 0)
				rw->reader_blocked--;
#ifdef	NISDB_MT_DEBUG
			else
				abort();
#endif	/* NISDB_MT_DEBUG */
		}
	}

	/* OK to grab the write lock */
	rw->writer.id = myself;
	/* Increment lock depth */
	rw->writer.count++;
	/* Set number of writers (doesn't increase with lock depth) */
	if (rw->writer_count == 0)
		rw->writer_count = 1;

	return (mutex_unlock(&rw->mutex));
}