@@ -0,0 +1,77 @@

.. _signal:

:c:type:`uv_signal_t` --- Signal handle
=======================================

Signal handles implement Unix style signal handling on a per-event loop bases.

Reception of some signals is emulated on Windows:

* SIGINT is normally delivered when the user presses CTRL+C. However, like
on Unix, it is not generated when terminal raw mode is enabled.

* SIGBREAK is delivered when the user pressed CTRL + BREAK.

* SIGHUP is generated when the user closes the console window. On SIGHUP the
program is given approximately 10 seconds to perform cleanup. After that
Windows will unconditionally terminate it.

* SIGWINCH is raised whenever libuv detects that the console has been
resized. SIGWINCH is emulated by libuv when the program uses a :c:type:`uv_tty_t`
handle to write to the console. SIGWINCH may not always be delivered in a
timely manner; libuv will only detect size changes when the cursor is
being moved. When a readable :c:type:`uv_tty_t` handle is used in raw mode,
resizing the console buffer will also trigger a SIGWINCH signal.

Watchers for other signals can be successfully created, but these signals
are never received. These signals are: `SIGILL`, `SIGABRT`, `SIGFPE`, `SIGSEGV`,
`SIGTERM` and `SIGKILL.`

Calls to raise() or abort() to programmatically raise a signal are
not detected by libuv; these will not trigger a signal watcher.

.. note::
On Linux SIGRT0 and SIGRT1 (signals 32 and 33) are used by the NPTL pthreads library to
manage threads. Installing watchers for those signals will lead to unpredictable behavior
and is strongly discouraged. Future versions of libuv may simply reject them.


Data types
----------

.. c:type:: uv_signal_t
Signal handle type.

.. c:type:: void (*uv_signal_cb)(uv_signal_t* handle, int signum)
Type definition for callback passed to :c:func:`uv_signal_start`.


Public members
^^^^^^^^^^^^^^

.. c:member:: int uv_signal_t.signum
Signal being monitored by this handle. Readonly.

.. seealso:: The :c:type:`uv_handle_t` members also apply.


API
---

.. c:function:: int uv_signal_init(uv_loop_t*, uv_signal_t* signal)
Initialize the handle.
.. c:function:: int uv_signal_start(uv_signal_t* signal, uv_signal_cb cb, int signum)
Start the handle with the given callback, watching for the given signal.
.. c:function:: int uv_signal_stop(uv_signal_t* signal)
Stop the handle, the callback will no longer be called.
.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<string>Template: White (2014-02-28 09:41)</string>
<string>M6.2.2-1878-1</string>
</array>
</plist>
@@ -0,0 +1 @@
F69E9CD9-EEF1-4223-9DA4-A1EA7FE112BA
Binary file not shown.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1,189 @@

.. _stream:

:c:type:`uv_stream_t` --- Stream handle
=======================================

Stream handles provide an abstraction of a duplex communication channel.
:c:type:`uv_stream_t` is an abstract type, libuv provides 3 stream implementations
in the for of :c:type:`uv_tcp_t`, :c:type:`uv_pipe_t` and :c:type:`uv_tty_t`.


Data types
----------

.. c:type:: uv_stream_t
Stream handle type.

.. c:type:: void (*uv_read_cb)(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
Callback called when data was read on a stream.

`nread` is > 0 if there is data available, 0 if libuv is done reading for
now, or < 0 on error.

The callee is responsible for stopping closing the stream when an error happens
by calling :c:func:`uv_read_stop` or :c:func:`uv_close`. Trying to read
from the stream again is undefined.

The callee is responsible for freeing the buffer, libuv does not reuse it.
The buffer may be a null buffer (where buf->base=NULL and buf->len=0) on
error.

.. c:type:: void (*uv_write_cb)(uv_write_t* req, int status)
Callback called after data was written on a stream. `status` will be 0 in
case of success, < 0 otherwise.

.. c:type:: void (*uv_connect_cb)(uv_connect_t* req, int status)
Callback called after a connection started by :c:func:`uv_connect` is done.
`status` will be 0 in case of success, < 0 otherwise.

.. c:type:: void (*uv_shutdown_cb)(uv_shutdown_t* req, int status)
Callback called after s shutdown request has been completed. `status` will
be 0 in case of success, < 0 otherwise.

.. c:type:: void (*uv_connection_cb)(uv_stream_t* server, int status)
Callback called when a stream server has received an incoming connection.
The user can accept the connection by calling :c:func:`uv_accept`.
`status` will de 0 in case of success, < 0 otherwise.


Public members
^^^^^^^^^^^^^^

.. c:member:: size_t uv_stream_t.write_queue_size
Contains the amount of queued bytes waiting to be sent. Readonly.

.. seealso:: The :c:type:`uv_handle_t` members also apply.


API
---

.. c:function:: int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb)
Shutdown the outgoing (write) side of a duplex stream. It waits for pending
write requests to complete. The `handle` should refer to a initialized stream.
`req` should be an uninitialized shutdown request struct. The `cb` is called
after shutdown is complete.
.. c:function:: int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb)
Start listening for incoming connections. `backlog` indicates the number of
connections the kernel might queue, same as ``listen(2)``. When a new
incoming connection is received the :c:type:`uv_connection_cb` callback is
called.
.. c:function:: int uv_accept(uv_stream_t* server, uv_stream_t* client)
This call is used in conjunction with :c:func:`uv_listen` to accept incoming
connections. Call this function after receiving a :c:type:`uv_connection_cb`
to accept the connection. Before calling this function the client handle must
be initialized. < 0 return value indicates an error.
When the :c:type:`uv_connection_cb` callback is called it is guaranteed that
this function will complete successfully the first time. If you attempt to use
it more than once, it may fail. It is suggested to only call this function once
per :c:type:`uv_connection_cb` call.
.. note::
`server` and `client` must be handles running on the same loop.
.. c:function:: int uv_read_start(uv_stream_t*, uv_alloc_cb alloc_cb, uv_read_cb read_cb)
Read data from an incoming stream. The callback will be made several
times until there is no more data to read or :c:func:`uv_read_stop` is called.
When we've reached EOF `nread` will be set to ``UV_EOF``.
When `nread` < 0, the `buf` parameter might not point to a valid buffer;
in that case `buf.len` and `buf.base` are both set to 0.
.. note::
`nread` might also be 0, which does *not* indicate an error or EOF, it happens when
libuv requested a buffer through the alloc callback but then decided that it didn't
need that buffer.
.. c:function:: int uv_read_stop(uv_stream_t*)
Stop reading data from the stream. The :c:type:`uv_read_cb` callback will
no longer be called.
.. c:function:: int uv_write(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb)
Write data to stream. Buffers are written in order. Example:
::
uv_buf_t a[] = {
{ .base = "1", .len = 1 },
{ .base = "2", .len = 1 }
};
uv_buf_t b[] = {
{ .base = "3", .len = 1 },
{ .base = "4", .len = 1 }
};
uv_write_t req1;
uv_write_t req2;
/* writes "1234" */
uv_write(&req1, stream, a, 2);
uv_write(&req2, stream, b, 2);
.. c:function:: int uv_write2(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, uv_write_cb cb)
Extended write function for sending handles over a pipe. The pipe must be
initialized with `ipc` == 1.
.. note::
`send_handle` must be a TCP socket or pipe, which is a server or a connection (listening
or connected state). Bound sockets or pipes will be assumed to be servers.
.. c:function:: int uv_try_write(uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs)
Same as :c:func:`uv_write`, but won't queue a write request if it can't be
completed immediately.
Will return either:
* > 0: number of bytes written (can be less than the supplied buffer size).
* < 0: negative error code (``UV_EAGAIN`` is returned if no data can be sent
immediately).
.. c:function:: int uv_is_readable(const uv_stream_t* handle)
Returns 1 if the stream is readable, 0 otherwise.
.. c:function:: int uv_is_writable(const uv_stream_t* handle)
Returns 1 if the stream is writable, 0 otherwise.
.. c:function:: int uv_stream_set_blocking(uv_stream_t* handle, int blocking)
Enable or disable blocking mode for a stream.
When blocking mode is enabled all writes complete synchronously. The
interface remains unchanged otherwise, e.g. completion or failure of the
operation will still be reported through a callback which is made
asychronously.
.. warning::
Relying too much on this API is not recommended. It is likely to change
significantly in the future.
Currently this only works on Windows and only for
:c:type:`uv_pipe_t` handles.
Also libuv currently makes no ordering guarantee when the blocking mode
is changed after write requests have already been submitted. Therefore it is
recommended to set the blocking mode immediately after opening or creating
the stream.
.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
@@ -0,0 +1,97 @@

.. _tcp:

:c:type:`uv_tcp_t` --- TCP handle
=================================

TCP handles are used to represent both TCP streams and servers.

:c:type:`uv_tcp_t` is a 'subclass' of :c:type:`uv_stream_t`.


Data types
----------

.. c:type:: uv_tcp_t
TCP handle type.


Public members
^^^^^^^^^^^^^^

N/A

.. seealso:: The :c:type:`uv_stream_t` members also apply.


API
---

.. c:function:: int uv_tcp_init(uv_loop_t*, uv_tcp_t* handle)
Initialize the handle.
.. c:function:: int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock)
Open an existing file descriptor or SOCKET as a TCP handle.
.. note::
The user is responsible for setting the file descriptor in
non-blocking mode.
.. c:function:: int uv_tcp_nodelay(uv_tcp_t* handle, int enable)
Enable / disable Nagle's algorithm.
.. c:function:: int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay)
Enable / disable TCP keep-alive. `delay` is the initial delay in seconds,
ignored when `enable` is zero.
.. c:function:: int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable)
Enable / disable simultaneous asynchronous accept requests that are
queued by the operating system when listening for new TCP connections.
This setting is used to tune a TCP server for the desired performance.
Having simultaneous accepts can significantly improve the rate of accepting
connections (which is why it is enabled by default) but may lead to uneven
load distribution in multi-process setups.
.. c:function:: int uv_tcp_bind(uv_tcp_t* handle, const struct sockaddr* addr, unsigned int flags)
Bind the handle to an address and port. `addr` should point to an
initialized ``struct sockaddr_in`` or ``struct sockaddr_in6``.
When the port is already taken, you can expect to see an ``UV_EADDRINUSE``
error from either :c:func:`uv_tcp_bind`, :c:func:`uv_listen` or
:c:func:`uv_tcp_connect`. That is, a successful call to this function does
not guarantee that the call to :c:func:`uv_listen` or :c:func:`uv_tcp_connect`
will succeed as well.
`flags` con contain ``UV_TCP_IPV6ONLY``, in which case dual-stack support
is disabled and only IPv6 is used.
.. c:function:: int uv_tcp_getsockname(const uv_tcp_t* handle, struct sockaddr* name, int* namelen)
Get the current address to which the handle is bound. `addr` must point to
a valid and big enough chunk of memory, ``struct sockaddr_storage`` is
recommended for IPv4 and IPv6 support.
.. c:function:: int uv_tcp_getpeername(const uv_tcp_t* handle, struct sockaddr* name, int* namelen)
Get the address of the peer connected to the handle. `addr` must point to
a valid and big enough chunk of memory, ``struct sockaddr_storage`` is
recommended for IPv4 and IPv6 support.
.. c:function:: int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle, const struct sockaddr* addr, uv_connect_cb cb)
Establish an IPv4 or IPv6 TCP connection. Provide an initialized TCP handle
and an uninitialized :c:type:`uv_connect_t`. `addr` should point to an
initialized ``struct sockaddr_in`` or ``struct sockaddr_in6``.
The callback is made when the connection has been established or when a
connection error happened.
.. seealso:: The :c:type:`uv_stream_t` API functions also apply.
@@ -0,0 +1,156 @@

.. _threading:

Threading and synchronization utilities
=======================================

libuv provides cross-platform implementations for multiple threading and
synchronization primitives. The API largely follows the pthreads API.


Data types
----------

.. c:type:: uv_thread_t
Thread data type.

.. c:type:: void (*uv_thread_cb)(void* arg)
Callback that is invoked to initialize thread execution. `arg` is the same
value that was passed to :c:func:`uv_thread_create`.

.. c:type:: uv_key_t
Thread-local key data type.

.. c:type:: uv_once_t
Once-only initializer data type.

.. c:type:: uv_mutex_t
Mutex data type.

.. c:type:: uv_rwlock_t
Read-write lock data type.

.. c:type:: uv_sem_t
Semaphore data type.

.. c:type:: uv_cond_t
Condition data type.

.. c:type:: uv_barrier_t
Barrier data type.


API
---

Threads
^^^^^^^

.. c:function:: int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg)
.. c:function:: unsigned long uv_thread_self(void)
.. c:function:: int uv_thread_join(uv_thread_t *tid)
Thread-local storage
^^^^^^^^^^^^^^^^^^^^
.. note::
The total thread-local storage size may be limited. That is, it may not be possible to
create many TLS keys.
.. c:function:: int uv_key_create(uv_key_t* key)
.. c:function:: void uv_key_delete(uv_key_t* key)
.. c:function:: void* uv_key_get(uv_key_t* key)
.. c:function:: void uv_key_set(uv_key_t* key, void* value)
Once-only initialization
^^^^^^^^^^^^^^^^^^^^^^^^
Runs a function once and only once. Concurrent calls to :c:func:`uv_once` with the
same guard will block all callers except one (it's unspecified which one).
The guard should be initialized statically with the UV_ONCE_INIT macro.
.. c:function:: void uv_once(uv_once_t* guard, void (*callback)(void))
Mutex locks
^^^^^^^^^^^
Functions return 0 on success or an error code < 0 (unless the
return type is void, of course).
.. c:function:: int uv_mutex_init(uv_mutex_t* handle)
.. c:function:: void uv_mutex_destroy(uv_mutex_t* handle)
.. c:function:: void uv_mutex_lock(uv_mutex_t* handle)
.. c:function:: int uv_mutex_trylock(uv_mutex_t* handle)
.. c:function:: void uv_mutex_unlock(uv_mutex_t* handle)
Read-write locks
^^^^^^^^^^^^^^^^
Functions return 0 on success or an error code < 0 (unless the
return type is void, of course).
.. c:function:: int uv_rwlock_init(uv_rwlock_t* rwlock)
.. c:function:: void uv_rwlock_destroy(uv_rwlock_t* rwlock)
.. c:function:: void uv_rwlock_rdlock(uv_rwlock_t* rwlock)
.. c:function:: int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock)
.. c:function:: void uv_rwlock_rdunlock(uv_rwlock_t* rwlock)
.. c:function:: void uv_rwlock_wrlock(uv_rwlock_t* rwlock)
.. c:function:: int uv_rwlock_trywrlock(uv_rwlock_t* rwlock)
.. c:function:: void uv_rwlock_wrunlock(uv_rwlock_t* rwlock)
Semaphores
^^^^^^^^^^
Functions return 0 on success or an error code < 0 (unless the
return type is void, of course).
.. c:function:: int uv_sem_init(uv_sem_t* sem, unsigned int value)
.. c:function:: void uv_sem_destroy(uv_sem_t* sem)
.. c:function:: void uv_sem_post(uv_sem_t* sem)
.. c:function:: void uv_sem_wait(uv_sem_t* sem)
.. c:function:: int uv_sem_trywait(uv_sem_t* sem)
Conditions
^^^^^^^^^^
Functions return 0 on success or an error code < 0 (unless the
return type is void, of course).
.. note::
Callers should be prepared to deal with spurious wakeups on :c:func:`uv_cond_wait` and
:c:func:`uv_cond_timedwait`.
.. c:function:: int uv_cond_init(uv_cond_t* cond)
.. c:function:: void uv_cond_destroy(uv_cond_t* cond)
.. c:function:: void uv_cond_signal(uv_cond_t* cond)
.. c:function:: void uv_cond_broadcast(uv_cond_t* cond)
.. c:function:: void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex)
.. c:function:: int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout)
Barriers
^^^^^^^^
Functions return 0 on success or an error code < 0 (unless the
return type is void, of course).
.. note::
:c:func:`uv_barrier_wait` returns a value > 0 to an arbitrarily chosen "serializer" thread
to facilitate cleanup, i.e.
::
if (uv_barrier_wait(&barrier) > 0)
uv_barrier_destroy(&barrier);
.. c:function:: int uv_barrier_init(uv_barrier_t* barrier, unsigned int count)
.. c:function:: void uv_barrier_destroy(uv_barrier_t* barrier)
.. c:function:: int uv_barrier_wait(uv_barrier_t* barrier)
@@ -0,0 +1,59 @@

.. _threadpool:

Thread pool work scheduling
===========================

libuv provides a threadpool which can be used to run user code and get notified
in the loop thread. This thread pool is internally used to run al filesystem
operations, as well as getaddrinfo and getnameinfo requests.

Its default size is 4, but it can be changed at startup time by setting the
``UV_THREADPOOL_SIZE`` environment variable to any value (the absolute maximum
is 128).

The threadpool is global and shared across all event loops.


Data types
----------

.. c:type:: uv_work_t
Work request type.

.. c:type:: void (*uv_work_cb)(uv_work_t* req)
Callback passed to :c:func:`uv_queue_work` which will be run on the thread
pool.

.. c:type:: void (*uv_after_work_cb)(uv_work_t* req, int status)
Callback passed to :c:func:`uv_queue_work` which will be called on the loop
thread after the work on the threadpool has been completed. If the work
was cancelled using :c:func:`uv_cancel` `status` will be ``UV_ECANCELED``.


Public members
^^^^^^^^^^^^^^

.. c:member:: uv_loop_t* uv_work_t.loop
Loop that started this request and where completion will be reported.
Readonly.

.. seealso:: The :c:type:`uv_req_t` members also apply.


API
---

.. c:function:: int uv_queue_work(uv_loop_t* loop, uv_work_t* req, uv_work_cb work_cb, uv_after_work_cb after_work_cb)
Initializes a work request which will run the given `work_cb` in a thread
from the threadpool. Once `work_cb` is completed, `after_work_cb` will be
called on the loop thread.
This request can be cancelled with :c:func:`uv_cancel`.
.. seealso:: The :c:type:`uv_req_t` API functions also apply.
@@ -0,0 +1,68 @@

.. _timer:

:c:type:`uv_timer_t` --- Timer handle
=====================================

Timer handles are used to schedule callbacks to be called in the future.


Data types
----------

.. c:type:: uv_timer_t
Timer handle type.

.. c:type:: void (*uv_timer_cb)(uv_timer_t* handle)
Type definition for callback passed to :c:func:`uv_timer_start`.


Public members
^^^^^^^^^^^^^^

N/A

.. seealso:: The :c:type:`uv_handle_t` members also apply.


API
---

.. c:function:: int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle)
Initialize the handle.
.. c:function:: int uv_timer_start(uv_timer_t* handle, uv_timer_cb cb, uint64_t timeout, uint64_t repeat)
Start the timer. `timeout` and `repeat` are in milliseconds.
If `timeout` is zero, the callback fires on the next event loop iteration.
If `repeat` is non-zero, the callback fires first after `timeout`
milliseconds and then repeatedly after `repeat` milliseconds.
.. c:function:: int uv_timer_stop(uv_timer_t* handle)
Stop the timer, the callback will not be called anymore.
.. c:function:: int uv_timer_again(uv_timer_t* handle)
Stop the timer, and if it is repeating restart it using the repeat value
as the timeout. If the timer has never been started before it returns
UV_EINVAL.
.. c:function:: void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat)
Set the repeat value in milliseconds.
.. note::
If the repeat value is set from a timer callback it does not immediately take effect.
If the timer was non-repeating before, it will have been stopped. If it was repeating,
then the old repeat value will have been used to schedule the next timeout.
.. c:function:: uint64_t uv_timer_get_repeat(const uv_timer_t* handle)
Get the timer repeat value.
.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
@@ -0,0 +1,63 @@

.. _tty:

:c:type:`uv_tty_t` --- TTY handle
=================================

TTY handles represent a stream for the console.

:c:type:`uv_tty_t` is a 'subclass' of :c:type:`uv_stream_t`.


Data types
----------

.. c:type:: uv_tty_t
TTY handle type.


Public members
^^^^^^^^^^^^^^

N/A

.. seealso:: The :c:type:`uv_stream_t` members also apply.


API
---

.. c:function:: int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable)
Initialize a new TTY stream with the given file descriptor. Usually the
file descriptor will be:
* 0 = stdin
* 1 = stdout
* 2 = stderr
`readable`, specifies if you plan on calling :c:func:`uv_read_start` with
this stream. stdin is readable, stdout is not.
.. note::
TTY streams which are not readable have blocking writes.
.. c:function:: int uv_tty_set_mode(uv_tty_t*, int mode)
Set the TTY mode. 0 for normal, 1 for raw.
.. c:function:: int uv_tty_reset_mode(void)
To be called when the program exits. Resets TTY settings to default
values for the next process to take over.
This function is async signal-safe on Unix platforms but can fail with error
code ``UV_EBUSY`` if you call it when execution is inside
:c:func:`uv_tty_set_mode`.
.. c:function:: int uv_tty_get_winsize(uv_tty_t*, int* width, int* height)
Gets the current Window size. On success it returns 0.
.. seealso:: The :c:type:`uv_stream_t` API functions also apply.
@@ -0,0 +1,280 @@

.. _udp:

:c:type:`uv_udp_t` --- UDP handle
=================================

UDP handles encapsulate UDP communication for both clients and servers.


Data types
----------

.. c:type:: uv_udp_t
UDP handle type.

.. c:type:: uv_udp_send_t
UDP send request type.

.. c:type:: uv_udp_flags
Flags used in :c:func:`uv_udp_bind` and :c:type:`uv_udp_recv_cb`..

::

enum uv_udp_flags {
/* Disables dual stack mode. */
UV_UDP_IPV6ONLY = 1,
/*
* Indicates message was truncated because read buffer was too small. The
* remainder was discarded by the OS. Used in uv_udp_recv_cb.
*/
UV_UDP_PARTIAL = 2,
/*
* Indicates if SO_REUSEADDR will be set when binding the handle in
* uv_udp_bind.
* This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other
* Unix platforms, it sets the SO_REUSEADDR flag. What that means is that
* multiple threads or processes can bind to the same address without error
* (provided they all set the flag) but only the last one to bind will receive
* any traffic, in effect "stealing" the port from the previous listener.
*/
UV_UDP_REUSEADDR = 4
};

.. c:type:: void (*uv_udp_send_cb)(uv_udp_send_t* req, int status)
Type definition for callback passed to :c:func:`uv_udp_send`, which is
called after the data was sent.

.. c:type:: void (*uv_udp_recv_cb)(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags)
Type definition for callback passed to :c:func:`uv_udp_recv_start`, which
is called when the endpoint receives data.

* `handle`: UDP handle
* `nread`: Number of bytes that have been received.
0 if there is no more data to read. You may discard or repurpose
the read buffer. Note that 0 may also mean that an empty datagram
was received (in this case `addr` is not NULL). < 0 if a transmission
error was detected.
* `buf`: :c:type:`uv_buf_t` with the received data.
* `addr`: ``struct sockaddr*`` containing the address of the sender.
Can be NULL. Valid for the duration of the callback only.
* `flags`: One or more or'ed UV_UDP_* constants. Right now only
``UV_UDP_PARTIAL`` is used.

.. note::
The receive callback will be called with `nread` == 0 and `addr` == NULL when there is
nothing to read, and with `nread` == 0 and `addr` != NULL when an empty UDP packet is
received.

.. c:type:: uv_membership
Membership type for a multicast address.

::

typedef enum {
UV_LEAVE_GROUP = 0,
UV_JOIN_GROUP
} uv_membership;


Public members
^^^^^^^^^^^^^^

.. c:member:: size_t uv_udp_t.send_queue_size
Number of bytes queued for sending. This field strictly shows how much
information is currently queued.

.. c:member:: size_t uv_udp_t.send_queue_count
Number of send requests currently in the queue awaiting to be processed.

.. c:member:: uv_udp_t* uv_udp_send_t.handle
UDP handle where this send request is taking place.

.. seealso:: The :c:type:`uv_handle_t` members also apply.


API
---

.. c:function:: int uv_udp_init(uv_loop_t*, uv_udp_t* handle)
Initialize a new UDP handle. The actual socket is created lazily.
Returns 0 on success.
.. c:function:: int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock)
Opens an existing file descriptor or Windows SOCKET as a UDP handle.
Unix only:
The only requirement of the `sock` argument is that it follows the datagram
contract (works in unconnected mode, supports sendmsg()/recvmsg(), etc).
In other words, other datagram-type sockets like raw sockets or netlink
sockets can also be passed to this function.
.. c:function:: int uv_udp_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int flags)
Bind the UDP handle to an IP address and port.
:param handle: UDP handle. Should have been initialized with
:c:func:`uv_udp_init`.
:param addr: `struct sockaddr_in` or `struct sockaddr_in6`
with the address and port to bind to.
:param flags: Indicate how the socket will be bound,
``UV_UDP_IPV6ONLY`` and ``UV_UDP_REUSEADDR`` are supported.
:returns: 0 on success, or an error code < 0 on failure.
.. c:function:: int uv_udp_getsockname(const uv_udp_t* handle, struct sockaddr* name, int* namelen)
Get the local IP and port of the UDP handle.
:param handle: UDP handle. Should have been initialized with
:c:func:`uv_udp_init` and bound.
:param name: Pointer to the structure to be filled with the address data.
In order to support IPv4 and IPv6 `struct sockaddr_storage` should be
used.
:param namelen: On input it indicates the data of the `name` field. On
output it indicates how much of it was filled.
:returns: 0 on success, or an error code < 0 on failure.
.. c:function:: int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, const char* interface_addr, uv_membership membership)
Set membership for a multicast address
:param handle: UDP handle. Should have been initialized with
:c:func:`uv_udp_init`.
:param multicast_addr: Multicast address to set membership for.
:param interface_addr: Interface address.
:param membership: Should be ``UV_JOIN_GROUP`` or ``UV_LEAVE_GROUP``.
:returns: 0 on success, or an error code < 0 on failure.
.. c:function:: int uv_udp_set_multicast_loop(uv_udp_t* handle, int on)
Set IP multicast loop flag. Makes multicast packets loop back to
local sockets.
:param handle: UDP handle. Should have been initialized with
:c:func:`uv_udp_init`.
:param on: 1 for on, 0 for off.
:returns: 0 on success, or an error code < 0 on failure.
.. c:function:: int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl)
Set the multicast ttl.
:param handle: UDP handle. Should have been initialized with
:c:func:`uv_udp_init`.
:param ttl: 1 through 255.
:returns: 0 on success, or an error code < 0 on failure.
.. c:function:: int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr)
Set the multicast interface to send or receive data on.
:param handle: UDP handle. Should have been initialized with
:c:func:`uv_udp_init`.
:param interface_addr: interface address.
:returns: 0 on success, or an error code < 0 on failure.
.. c:function:: int uv_udp_set_broadcast(uv_udp_t* handle, int on)
Set broadcast on or off.
:param handle: UDP handle. Should have been initialized with
:c:func:`uv_udp_init`.
:param on: 1 for on, 0 for off.
:returns: 0 on success, or an error code < 0 on failure.
.. c:function:: int uv_udp_set_ttl(uv_udp_t* handle, int ttl)
Set the time to live.
:param handle: UDP handle. Should have been initialized with
:c:func:`uv_udp_init`.
:param ttl: 1 through 255.
:returns: 0 on success, or an error code < 0 on failure.
.. c:function:: int uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr, uv_udp_send_cb send_cb)
Send data over the UDP socket. If the socket has not previously been bound
with :c:func:`uv_udp_bind` it will be bound to 0.0.0.0
(the "all interfaces" IPv4 address) and a random port number.
:param req: UDP request handle. Need not be initialized.
:param handle: UDP handle. Should have been initialized with
:c:func:`uv_udp_init`.
:param bufs: List of buffers to send.
:param nbufs: Number of buffers in `bufs`.
:param addr: `struct sockaddr_in` or `struct sockaddr_in6` with the
address and port of the remote peer.
:param send_cb: Callback to invoke when the data has been sent out.
:returns: 0 on success, or an error code < 0 on failure.
.. c:function:: int uv_udp_try_send(uv_udp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr)
Same as :c:func:`uv_udp_send`, but won't queue a send request if it can't
be completed immediately.
:returns: >= 0: number of bytes sent (it matches the given buffer size).
< 0: negative error code (``UV_EAGAIN`` is returned when the message
can't be sent immediately).
.. c:function:: int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb)
Prepare for receiving data. If the socket has not previously been bound
with :c:func:`uv_udp_bind` it is bound to 0.0.0.0 (the "all interfaces"
IPv4 address) and a random port number.
:param handle: UDP handle. Should have been initialized with
:c:func:`uv_udp_init`.
:param alloc_cb: Callback to invoke when temporary storage is needed.
:param recv_cb: Callback to invoke with received data.
:returns: 0 on success, or an error code < 0 on failure.
.. c:function:: int uv_udp_recv_stop(uv_udp_t* handle)
Stop listening for incoming datagrams.
:param handle: UDP handle. Should have been initialized with
:c:func:`uv_udp_init`.
:returns: 0 on success, or an error code < 0 on failure.
.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
@@ -57,12 +57,6 @@
# define UV__EACCES (-4092)
#endif

#if defined(EADDRINFO) && !defined(_WIN32)
# define UV__EADDRINFO EADDRINFO
#else
# define UV__EADDRINFO (-4091)
#endif

#if defined(EADDRINUSE) && !defined(_WIN32)
# define UV__EADDRINUSE (-EADDRINUSE)
#else
@@ -25,6 +25,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>

#include <sys/socket.h>
#include <netinet/in.h>
@@ -117,13 +118,14 @@ struct uv__async {
#endif

/* Note: May be cast to struct iovec. See writev(2). */
typedef struct {
typedef struct uv_buf_t {
char* base;
size_t len;
} uv_buf_t;

typedef int uv_file;
typedef int uv_os_sock_t;
typedef int uv_os_fd_t;

#define UV_ONCE_INIT PTHREAD_ONCE_INIT

@@ -155,6 +157,47 @@ typedef pthread_barrier_t uv_barrier_t;
typedef gid_t uv_gid_t;
typedef uid_t uv_uid_t;

typedef struct dirent uv__dirent_t;

#if defined(DT_UNKNOWN)
# define HAVE_DIRENT_TYPES
# if defined(DT_REG)
# define UV__DT_FILE DT_REG
# else
# define UV__DT_FILE -1
# endif
# if defined(DT_DIR)
# define UV__DT_DIR DT_DIR
# else
# define UV__DT_DIR -2
# endif
# if defined(DT_LNK)
# define UV__DT_LINK DT_LNK
# else
# define UV__DT_LINK -3
# endif
# if defined(DT_FIFO)
# define UV__DT_FIFO DT_FIFO
# else
# define UV__DT_FIFO -4
# endif
# if defined(DT_SOCK)
# define UV__DT_SOCKET DT_SOCK
# else
# define UV__DT_SOCKET -5
# endif
# if defined(DT_CHR)
# define UV__DT_CHAR DT_CHR
# else
# define UV__DT_CHAR -6
# endif
# if defined(DT_BLK)
# define UV__DT_BLOCK DT_BLK
# else
# define UV__DT_BLOCK -7
# endif
#endif

/* Platform-specific definitions for uv_dlopen support. */
#define UV_DYNAMIC /* empty */

@@ -176,7 +219,7 @@ typedef struct {
uv_async_t wq_async; \
uv_rwlock_t cloexec_lock; \
uv_handle_t* closing_handles; \
void* process_handles[1][2]; \
void* process_handles[2]; \
void* prepare_handles[2]; \
void* check_handles[2]; \
void* idle_handles[2]; \
@@ -23,16 +23,17 @@
#define UV_VERSION_H

/*
* Versions with an even minor version (e.g. 0.6.1 or 1.0.4) are API and ABI
* stable. When the minor version is odd, the API can change between patch
* releases. Make sure you update the -soname directives in configure.ac
* Versions with the same major number are ABI stable. API is allowed to
* evolve between minor releases, but only in a backwards compatible way.
* Make sure you update the -soname directives in configure.ac
* and uv.gyp whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but
* not UV_VERSION_PATCH.)
*/

#define UV_VERSION_MAJOR 0
#define UV_VERSION_MINOR 11
#define UV_VERSION_PATCH 28
#define UV_VERSION_MAJOR 1
#define UV_VERSION_MINOR 0
#define UV_VERSION_PATCH 0
#define UV_VERSION_IS_RELEASE 1
#define UV_VERSION_SUFFIX "rc1"

#endif /* UV_VERSION_H */
@@ -39,6 +39,20 @@ typedef struct pollfd {
} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD;
#endif

#ifndef LOCALE_INVARIANT
# define LOCALE_INVARIANT 0x007f
#endif

#ifndef _malloca
# if defined(_DEBUG)
# define _malloca(size) malloc(size)
# define _freea(ptr) free(ptr)
# else
# define _malloca(size) alloca(size)
# define _freea(ptr)
# endif
#endif

#include <mswsock.h>
#include <ws2tcpip.h>
#include <windows.h>
@@ -215,8 +229,8 @@ typedef struct uv_buf_t {
} uv_buf_t;

typedef int uv_file;

typedef SOCKET uv_os_sock_t;
typedef HANDLE uv_os_fd_t;

typedef HANDLE uv_thread_t;

@@ -275,6 +289,19 @@ typedef struct uv_once_s {
typedef unsigned char uv_uid_t;
typedef unsigned char uv_gid_t;

typedef struct uv__dirent_s {
int d_type;
char d_name[1];
} uv__dirent_t;

#define UV__DT_DIR UV_DIRENT_DIR
#define UV__DT_FILE UV_DIRENT_FILE
#define UV__DT_LINK UV_DIRENT_LINK
#define UV__DT_FIFO UV_DIRENT_FIFO
#define UV__DT_SOCKET UV_DIRENT_SOCKET
#define UV__DT_CHAR UV_DIRENT_CHAR
#define UV__DT_BLOCK UV_DIRENT_BLOCK

/* Platform-specific definitions for uv_dlopen support. */
#define UV_DYNAMIC FAR WINAPI
typedef struct {
@@ -289,8 +316,6 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
HANDLE iocp; \
/* The current time according to the event loop. in msecs. */ \
uint64_t time; \
/* GetTickCount() result when the event loop time was last updated. */ \
DWORD last_tick_count; \
/* Tail of a single-linked circular queue of pending reqs. If the queue */ \
/* is empty, tail_ is NULL. If there is only one item, */ \
/* tail_->next_req == tail_ */ \
@@ -443,7 +468,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
int queue_len; \
} pending_ipc_info; \
uv_write_t* non_overlapped_writes_tail; \
void* reserved;
uv_mutex_t readfile_mutex; \
volatile HANDLE readfile_thread;

#define UV_PIPE_PRIVATE_FIELDS \
HANDLE handle; \

Large diffs are not rendered by default.

@@ -1,2 +1,5 @@
# Ignore libtoolize-generated files.
*.m4
!as_case.m4
!dtrace.m4
!libuv-check-flags.m4
@@ -0,0 +1,21 @@
# AS_CASE(WORD, [PATTERN1], [IF-MATCHED1]...[DEFAULT])
# ----------------------------------------------------
# Expand into
# | case WORD in
# | PATTERN1) IF-MATCHED1 ;;
# | ...
# | *) DEFAULT ;;
# | esac
m4_define([_AS_CASE],
[m4_if([$#], 0, [m4_fatal([$0: too few arguments: $#])],
[$#], 1, [ *) $1 ;;],
[$#], 2, [ $1) m4_default([$2], [:]) ;;],
[ $1) m4_default([$2], [:]) ;;
$0(m4_shiftn(2, $@))])dnl
])
m4_defun([AS_CASE],
[m4_ifval([$2$3],
[case $1 in
_AS_CASE(m4_shift($@))
esac])])

@@ -0,0 +1,66 @@
dnl Copyright (C) 2009 Sun Microsystems
dnl This file is free software; Sun Microsystems
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.

dnl ---------------------------------------------------------------------------
dnl Macro: PANDORA_ENABLE_DTRACE
dnl ---------------------------------------------------------------------------
AC_DEFUN([PANDORA_ENABLE_DTRACE],[
AC_ARG_ENABLE([dtrace],
[AS_HELP_STRING([--disable-dtrace],
[enable DTrace USDT probes. @<:@default=yes@:>@])],
[ac_cv_enable_dtrace="$enableval"],
[ac_cv_enable_dtrace="yes"])
AS_IF([test "$ac_cv_enable_dtrace" = "yes"],[
AC_CHECK_PROGS([DTRACE], [dtrace])
AS_IF([test "x$ac_cv_prog_DTRACE" = "xdtrace"],[
AC_CACHE_CHECK([if dtrace works],[ac_cv_dtrace_works],[
cat >conftest.d <<_ACEOF
provider Example {
probe increment(int);
};
_ACEOF
$DTRACE -h -o conftest.h -s conftest.d 2>/dev/zero
AS_IF([test $? -eq 0],[ac_cv_dtrace_works=yes],
[ac_cv_dtrace_works=no])
rm -f conftest.h conftest.d
])
AS_IF([test "x$ac_cv_dtrace_works" = "xyes"],[
AC_DEFINE([HAVE_DTRACE], [1], [Enables DTRACE Support])
AC_CACHE_CHECK([if dtrace should instrument object files],
[ac_cv_dtrace_needs_objects],[
dnl DTrace on MacOSX does not use -G option
cat >conftest.d <<_ACEOF
provider Example {
probe increment(int);
};
_ACEOF
cat > conftest.c <<_ACEOF
#include "conftest.h"
void foo() {
EXAMPLE_INCREMENT(1);
}
_ACEOF
$DTRACE -h -o conftest.h -s conftest.d 2>/dev/zero
$CC -c -o conftest.o conftest.c
$DTRACE -G -o conftest.d.o -s conftest.d conftest.o 2>/dev/zero
AS_IF([test $? -eq 0],[ac_cv_dtrace_needs_objects=yes],
[ac_cv_dtrace_needs_objects=no])
rm -f conftest.d.o conftest.d conftest.h conftest.o conftest.c
])
])
AC_SUBST(DTRACEFLAGS) dnl TODO: test for -G on OSX
ac_cv_have_dtrace=yes
])])
AM_CONDITIONAL([HAVE_DTRACE], [test "x$ac_cv_dtrace_works" = "xyes"])
AM_CONDITIONAL([DTRACE_NEEDS_OBJECTS],
[test "x$ac_cv_dtrace_needs_objects" = "xyes"])
])
dnl ---------------------------------------------------------------------------
dnl End Macro: PANDORA_ENABLE_DTRACE
dnl ---------------------------------------------------------------------------
@@ -0,0 +1,319 @@
dnl Macros to check the presence of generic (non-typed) symbols.
dnl Copyright (c) 2006-2008 Diego Pettenà <flameeyes gmail com>
dnl Copyright (c) 2006-2008 xine project
dnl
dnl This program is free software; you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation; either version 3, or (at your option)
dnl any later version.
dnl
dnl This program is distributed in the hope that it will be useful,
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
dnl GNU General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with this program; if not, write to the Free Software
dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
dnl 02110-1301, USA.
dnl
dnl As a special exception, the copyright owners of the
dnl macro gives unlimited permission to copy, distribute and modify the
dnl configure scripts that are the output of Autoconf when processing the
dnl Macro. You need not follow the terms of the GNU General Public
dnl License when using or distributing such scripts, even though portions
dnl of the text of the Macro appear in them. The GNU General Public
dnl License (GPL) does govern all other use of the material that
dnl constitutes the Autoconf Macro.
dnl
dnl This special exception to the GPL applies to versions of the
dnl Autoconf Macro released by this project. When you make and
dnl distribute a modified version of the Autoconf Macro, you may extend
dnl this special exception to the GPL to apply to your modified version as
dnl well.

dnl Check if the flag is supported by compiler
dnl CC_CHECK_CFLAGS_SILENT([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])

AC_DEFUN([CC_CHECK_CFLAGS_SILENT], [
AC_CACHE_VAL(AS_TR_SH([cc_cv_cflags_$1]),
[ac_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $1"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([int a;])],
[eval "AS_TR_SH([cc_cv_cflags_$1])='yes'"],
[eval "AS_TR_SH([cc_cv_cflags_$1])='no'"])
CFLAGS="$ac_save_CFLAGS"
])
AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes],
[$2], [$3])
])

dnl Check if the flag is supported by compiler (cacheable)
dnl CC_CHECK_CFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])

AC_DEFUN([CC_CHECK_CFLAGS], [
AC_CACHE_CHECK([if $CC supports $1 flag],
AS_TR_SH([cc_cv_cflags_$1]),
CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here!
)
AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes],
[$2], [$3])
])

dnl CC_CHECK_CFLAG_APPEND(FLAG, [action-if-found], [action-if-not-found])
dnl Check for CFLAG and appends them to CFLAGS if supported
AC_DEFUN([CC_CHECK_CFLAG_APPEND], [
AC_CACHE_CHECK([if $CC supports $1 flag],
AS_TR_SH([cc_cv_cflags_$1]),
CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here!
)
AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes],
[CFLAGS="$CFLAGS $1"; DEBUG_CFLAGS="$DEBUG_CFLAGS $1"; $2], [$3])
])

dnl CC_CHECK_CFLAGS_APPEND([FLAG1 FLAG2], [action-if-found], [action-if-not])
AC_DEFUN([CC_CHECK_CFLAGS_APPEND], [
for flag in $1; do
CC_CHECK_CFLAG_APPEND($flag, [$2], [$3])
done
])

dnl Check if the flag is supported by linker (cacheable)
dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])

AC_DEFUN([CC_CHECK_LDFLAGS], [
AC_CACHE_CHECK([if $CC supports $1 flag],
AS_TR_SH([cc_cv_ldflags_$1]),
[ac_save_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS $1"
AC_LANG_PUSH([C])
AC_LINK_IFELSE([AC_LANG_SOURCE([int main() { return 1; }])],
[eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"],
[eval "AS_TR_SH([cc_cv_ldflags_$1])="])
AC_LANG_POP([C])
LDFLAGS="$ac_save_LDFLAGS"
])
AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes],
[$2], [$3])
])

dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for
dnl the current linker to avoid undefined references in a shared object.
AC_DEFUN([CC_NOUNDEFINED], [
dnl We check $host for which systems to enable this for.
AC_REQUIRE([AC_CANONICAL_HOST])
case $host in
dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads
dnl are requested, as different implementations are present; to avoid problems
dnl use -Wl,-z,defs only for those platform not behaving this way.
*-freebsd* | *-openbsd*) ;;
*)
dnl First of all check for the --no-undefined variant of GNU ld. This allows
dnl for a much more readable commandline, so that people can understand what
dnl it does without going to look for what the heck -z defs does.
for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do
CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"])
break
done
;;
esac
AC_SUBST([LDFLAGS_NOUNDEFINED])
])

dnl Check for a -Werror flag or equivalent. -Werror is the GCC
dnl and ICC flag that tells the compiler to treat all the warnings
dnl as fatal. We usually need this option to make sure that some
dnl constructs (like attributes) are not simply ignored.
dnl
dnl Other compilers don't support -Werror per se, but they support
dnl an equivalent flag:
dnl - Sun Studio compiler supports -errwarn=%all
AC_DEFUN([CC_CHECK_WERROR], [
AC_CACHE_CHECK(
[for $CC way to treat warnings as errors],
[cc_cv_werror],
[CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror],
[CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])])
])
])

AC_DEFUN([CC_CHECK_ATTRIBUTE], [
AC_REQUIRE([CC_CHECK_WERROR])
AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))],
AS_TR_SH([cc_cv_attribute_$1]),
[ac_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $cc_cv_werror"
AC_LANG_PUSH([C])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])],
[eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"],
[eval "AS_TR_SH([cc_cv_attribute_$1])='no'"])
AC_LANG_POP([C])
CFLAGS="$ac_save_CFLAGS"
])
AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes],
[AC_DEFINE(
AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1,
[Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))]
)
$4],
[$5])
])

AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [
CC_CHECK_ATTRIBUTE(
[constructor],,
[void __attribute__((constructor)) ctor() { int a; }],
[$1], [$2])
])

AC_DEFUN([CC_ATTRIBUTE_FORMAT], [
CC_CHECK_ATTRIBUTE(
[format], [format(printf, n, n)],
[void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }],
[$1], [$2])
])

AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [
CC_CHECK_ATTRIBUTE(
[format_arg], [format_arg(printf)],
[char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }],
[$1], [$2])
])

AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [
CC_CHECK_ATTRIBUTE(
[visibility_$1], [visibility("$1")],
[void __attribute__((visibility("$1"))) $1_function() { }],
[$2], [$3])
])

AC_DEFUN([CC_ATTRIBUTE_NONNULL], [
CC_CHECK_ATTRIBUTE(
[nonnull], [nonnull()],
[void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }],
[$1], [$2])
])

AC_DEFUN([CC_ATTRIBUTE_UNUSED], [
CC_CHECK_ATTRIBUTE(
[unused], ,
[void some_function(void *foo, __attribute__((unused)) void *bar);],
[$1], [$2])
])

AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [
CC_CHECK_ATTRIBUTE(
[sentinel], ,
[void some_function(void *foo, ...) __attribute__((sentinel));],
[$1], [$2])
])

AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [
CC_CHECK_ATTRIBUTE(
[deprecated], ,
[void some_function(void *foo, ...) __attribute__((deprecated));],
[$1], [$2])
])

AC_DEFUN([CC_ATTRIBUTE_ALIAS], [
CC_CHECK_ATTRIBUTE(
[alias], [weak, alias],
[void other_function(void *foo) { }
void some_function(void *foo) __attribute__((weak, alias("other_function")));],
[$1], [$2])
])

AC_DEFUN([CC_ATTRIBUTE_MALLOC], [
CC_CHECK_ATTRIBUTE(
[malloc], ,
[void * __attribute__((malloc)) my_alloc(int n);],
[$1], [$2])
])

AC_DEFUN([CC_ATTRIBUTE_PACKED], [
CC_CHECK_ATTRIBUTE(
[packed], ,
[struct astructure { char a; int b; long c; void *d; } __attribute__((packed));],
[$1], [$2])
])

AC_DEFUN([CC_ATTRIBUTE_CONST], [
CC_CHECK_ATTRIBUTE(
[const], ,
[int __attribute__((const)) twopow(int n) { return 1 << n; } ],
[$1], [$2])
])

AC_DEFUN([CC_FLAG_VISIBILITY], [
AC_REQUIRE([CC_CHECK_WERROR])
AC_CACHE_CHECK([if $CC supports -fvisibility=hidden],
[cc_cv_flag_visibility],
[cc_flag_visibility_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $cc_cv_werror"
CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden],
cc_cv_flag_visibility='yes',
cc_cv_flag_visibility='no')
CFLAGS="$cc_flag_visibility_save_CFLAGS"])
AS_IF([test "x$cc_cv_flag_visibility" = "xyes"],
[AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1,
[Define this if the compiler supports the -fvisibility flag])
$1],
[$2])
])

AC_DEFUN([CC_FUNC_EXPECT], [
AC_REQUIRE([CC_CHECK_WERROR])
AC_CACHE_CHECK([if compiler has __builtin_expect function],
[cc_cv_func_expect],
[ac_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $cc_cv_werror"
AC_LANG_PUSH([C])
AC_COMPILE_IFELSE([AC_LANG_SOURCE(
[int some_function() {
int a = 3;
return (int)__builtin_expect(a, 3);
}])],
[cc_cv_func_expect=yes],
[cc_cv_func_expect=no])
AC_LANG_POP([C])
CFLAGS="$ac_save_CFLAGS"
])
AS_IF([test "x$cc_cv_func_expect" = "xyes"],
[AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1,
[Define this if the compiler supports __builtin_expect() function])
$1],
[$2])
])

AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [
AC_REQUIRE([CC_CHECK_WERROR])
AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported],
[cc_cv_attribute_aligned],
[ac_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $cc_cv_werror"
AC_LANG_PUSH([C])
for cc_attribute_align_try in 64 32 16 8 4 2; do
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
int main() {
static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0;
return c;
}])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break])
done
AC_LANG_POP([C])
CFLAGS="$ac_save_CFLAGS"
])
if test "x$cc_cv_attribute_aligned" != "x"; then
AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned],
[Define the highest alignment supported])
fi
])
@@ -60,6 +60,7 @@ int uv_fs_poll_start(uv_fs_poll_t* handle,
struct poll_ctx* ctx;
uv_loop_t* loop;
size_t len;
int err;

if (uv__is_active(handle))
return 0;
@@ -78,19 +79,25 @@ int uv_fs_poll_start(uv_fs_poll_t* handle,
ctx->parent_handle = handle;
memcpy(ctx->path, path, len + 1);

if (uv_timer_init(loop, &ctx->timer_handle))
abort();
err = uv_timer_init(loop, &ctx->timer_handle);
if (err < 0)
goto error;

ctx->timer_handle.flags |= UV__HANDLE_INTERNAL;
uv__handle_unref(&ctx->timer_handle);

if (uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb))
abort();
err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb);
if (err < 0)
goto error;

handle->poll_ctx = ctx;
uv__handle_start(handle);

return 0;

error:
free(ctx);
return err;
}


@@ -163,6 +163,33 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
uv__make_close_pending(handle);
}

int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
int r;
int fd;
socklen_t len;

if (handle == NULL || value == NULL)
return -EINVAL;

if (handle->type == UV_TCP || handle->type == UV_NAMED_PIPE)
fd = uv__stream_fd((uv_stream_t*) handle);
else if (handle->type == UV_UDP)
fd = ((uv_udp_t *) handle)->io_watcher.fd;
else
return -ENOTSUP;

len = sizeof(*value);

if (*value == 0)
r = getsockopt(fd, SOL_SOCKET, optname, value, &len);
else
r = setsockopt(fd, SOL_SOCKET, optname, (const void*) value, len);

if (r < 0)
return -errno;

return 0;
}

void uv__make_close_pending(uv_handle_t* handle) {
assert(handle->flags & UV_CLOSING);
@@ -635,6 +662,36 @@ void uv_disable_stdio_inheritance(void) {
}


int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
int fd_out;

switch (handle->type) {
case UV_TCP:
case UV_NAMED_PIPE:
case UV_TTY:
fd_out = uv__stream_fd((uv_stream_t*) handle);
break;

case UV_UDP:
fd_out = ((uv_udp_t *) handle)->io_watcher.fd;
break;

case UV_POLL:
fd_out = ((uv_poll_t *) handle)->io_watcher.fd;
break;

default:
return -EINVAL;
}

if (uv__is_closing(handle) || fd_out == -1)
return -EBADF;

*fd = fd_out;
return 0;
}


static void uv__run_pending(uv_loop_t* loop) {
QUEUE* q;
uv__io_t* w;
@@ -36,7 +36,7 @@ static int uv__pthread_setname_np(const char* name) {
int err;

/* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */
dynamic_pthread_setname_np = dlsym(RTLD_DEFAULT, "pthread_setname_np");
*(void **)(&dynamic_pthread_setname_np) = dlsym(RTLD_DEFAULT, "pthread_setname_np");
if (dynamic_pthread_setname_np == NULL)
return -ENOSYS;

@@ -94,13 +94,13 @@ int uv__set_process_title(const char* title) {
if (application_services_handle == NULL || core_foundation_handle == NULL)
goto out;

pCFStringCreateWithCString =
*(void **)(&pCFStringCreateWithCString) =
dlsym(core_foundation_handle, "CFStringCreateWithCString");
pCFBundleGetBundleWithIdentifier =
*(void **)(&pCFBundleGetBundleWithIdentifier) =
dlsym(core_foundation_handle, "CFBundleGetBundleWithIdentifier");
pCFBundleGetDataPointerForName =
*(void **)(&pCFBundleGetDataPointerForName) =
dlsym(core_foundation_handle, "CFBundleGetDataPointerForName");
pCFBundleGetFunctionPointerForName =
*(void **)(&pCFBundleGetFunctionPointerForName) =
dlsym(core_foundation_handle, "CFBundleGetFunctionPointerForName");

if (pCFStringCreateWithCString == NULL ||
@@ -118,14 +118,14 @@ int uv__set_process_title(const char* title) {
if (launch_services_bundle == NULL)
goto out;

pLSGetCurrentApplicationASN =
*(void **)(&pLSGetCurrentApplicationASN) =
pCFBundleGetFunctionPointerForName(launch_services_bundle,
S("_LSGetCurrentApplicationASN"));

if (pLSGetCurrentApplicationASN == NULL)
goto out;

pLSSetApplicationInformationItem =
*(void **)(&pLSSetApplicationInformationItem) =
pCFBundleGetFunctionPointerForName(launch_services_bundle,
S("_LSSetApplicationInformationItem"));

@@ -138,9 +138,9 @@ int uv__set_process_title(const char* title) {
if (display_name_key == NULL || *display_name_key == NULL)
goto out;

pCFBundleGetInfoDictionary = dlsym(core_foundation_handle,
*(void **)(&pCFBundleGetInfoDictionary) = dlsym(core_foundation_handle,
"CFBundleGetInfoDictionary");
pCFBundleGetMainBundle = dlsym(core_foundation_handle,
*(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle,
"CFBundleGetMainBundle");
if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL)
goto out;
@@ -152,13 +152,13 @@ int uv__set_process_title(const char* title) {
if (hi_services_bundle == NULL)
goto out;

pSetApplicationIsDaemon = pCFBundleGetFunctionPointerForName(
*(void **)(&pSetApplicationIsDaemon) = pCFBundleGetFunctionPointerForName(
hi_services_bundle,
S("SetApplicationIsDaemon"));
pLSApplicationCheckIn = pCFBundleGetFunctionPointerForName(
*(void **)(&pLSApplicationCheckIn) = pCFBundleGetFunctionPointerForName(
launch_services_bundle,
S("_LSApplicationCheckIn"));
pLSSetApplicationLaunchServicesServerConnectionStatus =
*(void **)(&pLSSetApplicationLaunchServicesServerConnectionStatus) =
pCFBundleGetFunctionPointerForName(
launch_services_bundle,
S("_LSSetApplicationLaunchServicesServerConnectionStatus"));
@@ -38,7 +38,6 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <pthread.h>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <utime.h>
@@ -296,22 +295,18 @@ static ssize_t uv__fs_read(uv_fs_t* req) {


#if defined(__OpenBSD__) || (defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8))
static int uv__fs_readdir_filter(struct dirent* dent) {
static int uv__fs_readdir_filter(uv__dirent_t* dent) {
#else
static int uv__fs_readdir_filter(const struct dirent* dent) {
static int uv__fs_readdir_filter(const uv__dirent_t* dent) {
#endif
return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0;
}


/* This should have been called uv__fs_scandir(). */
static ssize_t uv__fs_readdir(uv_fs_t* req) {
struct dirent **dents;
uv__dirent_t **dents;
int saved_errno;
size_t off;
size_t len;
char *buf;
int i;
int n;

dents = NULL;
@@ -322,32 +317,17 @@ static ssize_t uv__fs_readdir(uv_fs_t* req) {
else if (n == -1)
return n;

len = 0;

for (i = 0; i < n; i++)
len += strlen(dents[i]->d_name) + 1;

buf = malloc(len);

if (buf == NULL) {
errno = ENOMEM;
n = -1;
goto out;
}

off = 0;

for (i = 0; i < n; i++) {
len = strlen(dents[i]->d_name) + 1;
memcpy(buf + off, dents[i]->d_name, len);
off += len;
}
/* NOTE: We will use nbufs as an index field */
req->ptr = dents;
req->nbufs = 0;

req->ptr = buf;
return n;

out:
saved_errno = errno;
if (dents != NULL) {
int i;

for (i = 0; i < n; i++)
free(dents[i]);
free(dents);
@@ -1184,6 +1164,9 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
req->path = NULL;
req->new_path = NULL;

if (req->fs_type == UV_FS_READDIR && req->ptr != NULL)
uv__fs_readdir_cleanup(req);

if (req->ptr != &req->statbuf)
free(req->ptr);
req->ptr = NULL;
@@ -525,7 +525,7 @@ static int uv__fsevents_global_init(void) {
err = -ENOENT;
#define V(handle, symbol) \
do { \
p ## symbol = dlsym((handle), #symbol); \
*(void **)(&p ## symbol) = dlsym((handle), #symbol); \
if (p ## symbol == NULL) \
goto out; \
} \
@@ -18,6 +18,13 @@
* IN THE SOFTWARE.
*/

/* Expose glibc-specific EAI_* error codes. Needs to be defined before we
* include any headers.
*/
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif

#include "uv.h"
#include "internal.h"

@@ -26,6 +33,66 @@
#include <stdlib.h>
#include <string.h>

/* EAI_* constants. */
#include <netdb.h>


int uv__getaddrinfo_translate_error(int sys_err) {
switch (sys_err) {
case 0: return 0;
#if defined(EAI_ADDRFAMILY)
case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY;
#endif
#if defined(EAI_AGAIN)
case EAI_AGAIN: return UV_EAI_AGAIN;
#endif
#if defined(EAI_BADFLAGS)
case EAI_BADFLAGS: return UV_EAI_BADFLAGS;
#endif
#if defined(EAI_BADHINTS)
case EAI_BADHINTS: return UV_EAI_BADHINTS;
#endif
#if defined(EAI_CANCELED)
case EAI_CANCELED: return UV_EAI_CANCELED;
#endif
#if defined(EAI_FAIL)
case EAI_FAIL: return UV_EAI_FAIL;
#endif
#if defined(EAI_FAMILY)
case EAI_FAMILY: return UV_EAI_FAMILY;
#endif
#if defined(EAI_MEMORY)
case EAI_MEMORY: return UV_EAI_MEMORY;
#endif
#if defined(EAI_NODATA)
case EAI_NODATA: return UV_EAI_NODATA;
#endif
#if defined(EAI_NONAME)
# if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME
case EAI_NONAME: return UV_EAI_NONAME;
# endif
#endif
#if defined(EAI_OVERFLOW)
case EAI_OVERFLOW: return UV_EAI_OVERFLOW;
#endif
#if defined(EAI_PROTOCOL)
case EAI_PROTOCOL: return UV_EAI_PROTOCOL;
#endif
#if defined(EAI_SERVICE)
case EAI_SERVICE: return UV_EAI_SERVICE;
#endif
#if defined(EAI_SOCKTYPE)
case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE;
#endif
#if defined(EAI_SYSTEM)
case EAI_SYSTEM: return -errno;
#endif
}
assert(!"unknown EAI_* error code");
abort();
return 0; /* Pacify compiler. */
}


static void uv__getaddrinfo_work(struct uv__work* w) {
uv_getaddrinfo_t* req;
@@ -143,7 +143,7 @@ enum {
UV_TCP_NODELAY = 0x400, /* Disable Nagle. */
UV_TCP_KEEPALIVE = 0x800, /* Turn on keep-alive. */
UV_TCP_SINGLE_ACCEPT = 0x1000, /* Only accept() when idle. */
UV_HANDLE_IPV6 = 0x2000 /* Handle is bound to a IPv6 socket. */
UV_HANDLE_IPV6 = 0x10000 /* Handle is bound to a IPv6 socket. */
};

typedef enum {
@@ -149,6 +149,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
int fd;
int op;
int i;
static int no_epoll_wait;

if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
@@ -195,10 +196,22 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
count = 48; /* Benchmarks suggest this gives the best throughput. */

for (;;) {
nfds = uv__epoll_wait(loop->backend_fd,
events,
ARRAY_SIZE(events),
timeout);
if (!no_epoll_wait) {
nfds = uv__epoll_wait(loop->backend_fd,
events,
ARRAY_SIZE(events),
timeout);
if (nfds == -1 && errno == ENOSYS) {
no_epoll_wait = 1;
continue;
}
} else {
nfds = uv__epoll_pwait(loop->backend_fd,
events,
ARRAY_SIZE(events),
timeout,
NULL);
}

/* Update loop->time unconditionally. It's tempting to skip the update when
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
@@ -99,7 +99,6 @@ void uv_loop_delete(uv_loop_t* loop) {


static int uv__loop_init(uv_loop_t* loop, int default_loop) {
unsigned int i;
int err;

uv__signal_global_once_init();
@@ -138,9 +137,7 @@ static int uv__loop_init(uv_loop_t* loop, int default_loop) {
uv_signal_init(loop, &loop->child_watcher);
uv__handle_unref(&loop->child_watcher);
loop->child_watcher.flags |= UV__HANDLE_INTERNAL;

for (i = 0; i < ARRAY_SIZE(loop->process_handles); i++)
QUEUE_INIT(loop->process_handles + i);
QUEUE_INIT(&loop->process_handles);

if (uv_rwlock_init(&loop->cloexec_lock))
abort();
@@ -38,6 +38,7 @@
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <uvm/uvm_extern.h>

#include <unistd.h>
#include <time.h>
@@ -45,77 +45,65 @@ extern char **environ;
#endif


static QUEUE* uv__process_queue(uv_loop_t* loop, int pid) {
assert(pid > 0);
return loop->process_handles + pid % ARRAY_SIZE(loop->process_handles);
}


static void uv__chld(uv_signal_t* handle, int signum) {
uv_process_t* process;
uv_loop_t* loop;
int exit_status;
int term_signal;
unsigned int i;
int status;
pid_t pid;
QUEUE pending;
QUEUE* h;
QUEUE* q;
QUEUE* h;

assert(signum == SIGCHLD);

QUEUE_INIT(&pending);
loop = handle->loop;

for (i = 0; i < ARRAY_SIZE(loop->process_handles); i++) {
h = loop->process_handles + i;
q = QUEUE_HEAD(h);
h = &loop->process_handles;
q = QUEUE_HEAD(h);
while (q != h) {
process = QUEUE_DATA(q, uv_process_t, queue);
q = QUEUE_NEXT(q);

while (q != h) {
process = QUEUE_DATA(q, uv_process_t, queue);
q = QUEUE_NEXT(q);
do
pid = waitpid(process->pid, &status, WNOHANG);
while (pid == -1 && errno == EINTR);

do
pid = waitpid(process->pid, &status, WNOHANG);
while (pid == -1 && errno == EINTR);

if (pid == 0)
continue;

if (pid == -1) {
if (errno != ECHILD)
abort();
continue;
}
if (pid == 0)
continue;

process->status = status;
QUEUE_REMOVE(&process->queue);
QUEUE_INSERT_TAIL(&pending, &process->queue);
if (pid == -1) {
if (errno != ECHILD)
abort();
continue;
}

while (!QUEUE_EMPTY(&pending)) {
q = QUEUE_HEAD(&pending);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
process->status = status;
QUEUE_REMOVE(&process->queue);
QUEUE_INSERT_TAIL(&pending, &process->queue);
}

process = QUEUE_DATA(q, uv_process_t, queue);
uv__handle_stop(process);
QUEUE_FOREACH(q, &pending) {
process = QUEUE_DATA(q, uv_process_t, queue);
QUEUE_REMOVE(q);
uv__handle_stop(process);

if (process->exit_cb == NULL)
continue;
if (process->exit_cb == NULL)
continue;

exit_status = 0;
if (WIFEXITED(process->status))
exit_status = WEXITSTATUS(process->status);
exit_status = 0;
if (WIFEXITED(process->status))
exit_status = WEXITSTATUS(process->status);

term_signal = 0;
if (WIFSIGNALED(process->status))
term_signal = WTERMSIG(process->status);
term_signal = 0;
if (WIFSIGNALED(process->status))
term_signal = WTERMSIG(process->status);

process->exit_cb(process, exit_status, term_signal);
}
process->exit_cb(process, exit_status, term_signal);
}
assert(QUEUE_EMPTY(&pending));
}


@@ -369,7 +357,6 @@ int uv_spawn(uv_loop_t* loop,
int signal_pipe[2] = { -1, -1 };
int (*pipes)[2];
int stdio_count;
QUEUE* q;
ssize_t r;
pid_t pid;
int err;
@@ -483,8 +470,7 @@ int uv_spawn(uv_loop_t* loop,

/* Only activate this handle if exec() happened successfully */
if (exec_errorno == 0) {
q = uv__process_queue(loop, pid);
QUEUE_INSERT_TAIL(q, &process->queue);
QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue);
uv__handle_start(process);
}

@@ -526,7 +512,8 @@ int uv_kill(int pid, int signum) {


void uv__process_close(uv_process_t* handle) {
/* TODO stop signal watcher when this is the last handle */
QUEUE_REMOVE(&handle->queue);
uv__handle_stop(handle);
if (QUEUE_EMPTY(&handle->loop->process_handles))
uv_signal_stop(&handle->loop->child_watcher);
}
@@ -53,6 +53,10 @@ struct uv__stream_select_s {
int fake_fd;
int int_fd;
int fd;
fd_set* sread;
size_t sread_sz;
fd_set* swrite;
size_t swrite_sz;
};
#endif /* defined(__APPLE__) */

@@ -127,8 +131,6 @@ static void uv__stream_osx_select(void* arg) {
uv_stream_t* stream;
uv__stream_select_t* s;
char buf[1024];
fd_set sread;
fd_set swrite;
int events;
int fd;
int r;
@@ -149,17 +151,17 @@ static void uv__stream_osx_select(void* arg) {
break;

/* Watch fd using select(2) */
FD_ZERO(&sread);
FD_ZERO(&swrite);
memset(s->sread, 0, s->sread_sz);
memset(s->swrite, 0, s->swrite_sz);

if (uv__io_active(&stream->io_watcher, UV__POLLIN))
FD_SET(fd, &sread);
FD_SET(fd, s->sread);
if (uv__io_active(&stream->io_watcher, UV__POLLOUT))
FD_SET(fd, &swrite);
FD_SET(s->int_fd, &sread);
FD_SET(fd, s->swrite);
FD_SET(s->int_fd, s->sread);

/* Wait indefinitely for fd events */
r = select(max_fd + 1, &sread, &swrite, NULL, NULL);
r = select(max_fd + 1, s->sread, s->swrite, NULL, NULL);
if (r == -1) {
if (errno == EINTR)
continue;
@@ -173,7 +175,7 @@ static void uv__stream_osx_select(void* arg) {
continue;

/* Empty socketpair's buffer in case of interruption */
if (FD_ISSET(s->int_fd, &sread))
if (FD_ISSET(s->int_fd, s->sread))
while (1) {
r = read(s->int_fd, buf, sizeof(buf));

@@ -194,12 +196,12 @@ static void uv__stream_osx_select(void* arg) {

/* Handle events */
events = 0;
if (FD_ISSET(fd, &sread))
if (FD_ISSET(fd, s->sread))
events |= UV__POLLIN;
if (FD_ISSET(fd, &swrite))
if (FD_ISSET(fd, s->swrite))
events |= UV__POLLOUT;

assert(events != 0 || FD_ISSET(s->int_fd, &sread));
assert(events != 0 || FD_ISSET(s->int_fd, s->sread));
if (events != 0) {
ACCESS_ONCE(int, s->events) = events;

@@ -261,6 +263,9 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) {
int ret;
int kq;
int old_fd;
int max_fd;
size_t sread_sz;
size_t swrite_sz;

kq = kqueue();
if (kq == -1) {
@@ -284,31 +289,48 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) {
return 0;

/* At this point we definitely know that this fd won't work with kqueue */
s = malloc(sizeof(*s));
if (s == NULL)
return -ENOMEM;

/*
* Create fds for io watcher and to interrupt the select() loop.
* NOTE: do it ahead of malloc below to allocate enough space for fd_sets
*/
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
return -errno;

max_fd = *fd;
if (fds[1] > max_fd)
max_fd = fds[1];

sread_sz = (max_fd + NBBY) / NBBY;
swrite_sz = sread_sz;

s = malloc(sizeof(*s) + sread_sz + swrite_sz);
if (s == NULL) {
err = -ENOMEM;
goto failed_malloc;
}

s->events = 0;
s->fd = *fd;
s->sread = (fd_set*) ((char*) s + sizeof(*s));
s->sread_sz = sread_sz;
s->swrite = (fd_set*) ((char*) s->sread + sread_sz);
s->swrite_sz = swrite_sz;

err = uv_async_init(stream->loop, &s->async, uv__stream_osx_select_cb);
if (err) {
free(s);
return err;
}
if (err)
goto failed_async_init;

s->async.flags |= UV__HANDLE_INTERNAL;
uv__handle_unref(&s->async);

if (uv_sem_init(&s->close_sem, 0))
goto fatal1;

if (uv_sem_init(&s->async_sem, 0))
goto fatal2;
err = uv_sem_init(&s->close_sem, 0);
if (err != 0)
goto failed_close_sem_init;

/* Create fds for io watcher and to interrupt the select() loop. */
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
goto fatal3;
err = uv_sem_init(&s->async_sem, 0);
if (err != 0)
goto failed_async_sem_init;

s->fake_fd = fds[0];
s->int_fd = fds[1];
@@ -318,26 +340,36 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) {
stream->select = s;
*fd = s->fake_fd;

if (uv_thread_create(&s->thread, uv__stream_osx_select, stream))
goto fatal4;
err = uv_thread_create(&s->thread, uv__stream_osx_select, stream);
if (err != 0)
goto failed_thread_create;

return 0;

fatal4:
failed_thread_create:
s->stream = NULL;
stream->select = NULL;
*fd = old_fd;
uv__close(s->fake_fd);
uv__close(s->int_fd);
s->fake_fd = -1;
s->int_fd = -1;
fatal3:

uv_sem_destroy(&s->async_sem);
fatal2:

failed_async_sem_init:
uv_sem_destroy(&s->close_sem);
fatal1:

failed_close_sem_init:
uv__close(fds[0]);
uv__close(fds[1]);
uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close);
return -errno;
return err;

failed_async_init:
free(s);

failed_malloc:
uv__close(fds[0]);
uv__close(fds[1]);

return err;
}
#endif /* defined(__APPLE__) */

@@ -361,10 +393,22 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
}


void uv__stream_destroy(uv_stream_t* stream) {
void uv__stream_flush_write_queue(uv_stream_t* stream, int error) {
uv_write_t* req;
QUEUE* q;
while (!QUEUE_EMPTY(&stream->write_queue)) {
q = QUEUE_HEAD(&stream->write_queue);
QUEUE_REMOVE(q);

req = QUEUE_DATA(q, uv_write_t, queue);
req->error = error;

QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue);
}
}


void uv__stream_destroy(uv_stream_t* stream) {
assert(!uv__io_active(&stream->io_watcher, UV__POLLIN | UV__POLLOUT));
assert(stream->flags & UV_CLOSED);

@@ -374,16 +418,7 @@ void uv__stream_destroy(uv_stream_t* stream) {
stream->connect_req = NULL;
}

while (!QUEUE_EMPTY(&stream->write_queue)) {
q = QUEUE_HEAD(&stream->write_queue);
QUEUE_REMOVE(q);

req = QUEUE_DATA(q, uv_write_t, queue);
req->error = -ECANCELED;

QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue);
}

uv__stream_flush_write_queue(stream, -ECANCELED);
uv__write_callbacks(stream);

if (stream->shutdown_req) {
@@ -537,7 +572,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
break;

default:
assert(0);
return -EINVAL;
}

done:
@@ -573,7 +608,6 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
int err;

err = -EINVAL;
switch (stream->type) {
case UV_TCP:
err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
@@ -584,7 +618,7 @@ int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
break;

default:
assert(0);
err = -EINVAL;
}

if (err == 0)
@@ -1163,7 +1197,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
assert(uv__stream_fd(stream) >= 0);

/* Ignore POLLHUP here. Even it it's set, there may still be data to read. */
if (events & (UV__POLLIN | UV__POLLERR))
if (events & (UV__POLLIN | UV__POLLERR | UV__POLLHUP))
uv__read(stream);

if (uv__stream_fd(stream) == -1)
@@ -1233,10 +1267,21 @@ static void uv__stream_connect(uv_stream_t* stream) {

stream->connect_req = NULL;
uv__req_unregister(stream->loop, req);
uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT);

if (error < 0 || QUEUE_EMPTY(&stream->write_queue)) {
uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT);
}

if (req->cb)
req->cb(req, error);

if (uv__stream_fd(stream) == -1)
return;

if (error < 0) {
uv__stream_flush_write_queue(stream, -ECANCELED);
uv__write_callbacks(stream);
}
}


@@ -65,6 +65,9 @@ int uv_timer_start(uv_timer_t* handle,
uint64_t repeat) {
uint64_t clamped_timeout;

if (cb == NULL)
return -EINVAL;

if (uv__is_active(handle))
uv_timer_stop(handle);

@@ -340,8 +340,6 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
unsigned char taddr[sizeof(struct sockaddr_in6)];
socklen_t addrlen;

assert(domain == AF_INET || domain == AF_INET6);

if (handle->io_watcher.fd != -1)
return 0;

@@ -19,13 +19,6 @@
* IN THE SOFTWARE.
*/

/* Expose glibc-specific EAI_* error codes. Needs to be defined before we
* include any headers.
*/
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif

#include "uv.h"
#include "uv-common.h"

@@ -39,13 +32,6 @@
# include <net/if.h> /* if_nametoindex */
#endif

/* EAI_* constants. */
#if !defined(_WIN32)
# include <sys/types.h>
# include <sys/socket.h>
# include <netdb.h>
#endif

#define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t);

size_t uv_handle_size(uv_handle_type type) {
@@ -410,62 +396,6 @@ uint64_t uv_now(const uv_loop_t* loop) {
}


int uv__getaddrinfo_translate_error(int sys_err) {
switch (sys_err) {
case 0: return 0;
#if defined(EAI_ADDRFAMILY)
case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY;
#endif
#if defined(EAI_AGAIN)
case EAI_AGAIN: return UV_EAI_AGAIN;
#endif
#if defined(EAI_BADFLAGS)
case EAI_BADFLAGS: return UV_EAI_BADFLAGS;
#endif
#if defined(EAI_BADHINTS)
case EAI_BADHINTS: return UV_EAI_BADHINTS;
#endif
#if defined(EAI_CANCELED)
case EAI_CANCELED: return UV_EAI_CANCELED;
#endif
#if defined(EAI_FAIL)
case EAI_FAIL: return UV_EAI_FAIL;
#endif
#if defined(EAI_FAMILY)
case EAI_FAMILY: return UV_EAI_FAMILY;
#endif
#if defined(EAI_MEMORY)
case EAI_MEMORY: return UV_EAI_MEMORY;
#endif
#if defined(EAI_NODATA)
case EAI_NODATA: return UV_EAI_NODATA;
#endif
#if defined(EAI_NONAME)
# if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME
case EAI_NONAME: return UV_EAI_NONAME;
# endif
#endif
#if defined(EAI_OVERFLOW)
case EAI_OVERFLOW: return UV_EAI_OVERFLOW;
#endif
#if defined(EAI_PROTOCOL)
case EAI_PROTOCOL: return UV_EAI_PROTOCOL;
#endif
#if defined(EAI_SERVICE)
case EAI_SERVICE: return UV_EAI_SERVICE;
#endif
#if defined(EAI_SOCKTYPE)
case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE;
#endif
#if defined(EAI_SYSTEM)
case EAI_SYSTEM: return -errno;
#endif
}
assert(!"unknown EAI_* error code");
abort();
return 0; /* Pacify compiler. */
}


size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) {
unsigned int i;
@@ -478,6 +408,13 @@ size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) {
return bytes;
}

int uv_recv_buffer_size(uv_handle_t* handle, int* value) {
return uv__socket_sockopt(handle, SO_RCVBUF, value);
}

int uv_send_buffer_size(uv_handle_t* handle, int *value) {
return uv__socket_sockopt(handle, SO_SNDBUF, value);
}

int uv_fs_event_getpath(uv_fs_event_t* handle, char* buf, size_t* len) {
size_t required_len;
@@ -498,3 +435,68 @@ int uv_fs_event_getpath(uv_fs_event_t* handle, char* buf, size_t* len) {

return 0;
}


void uv__fs_readdir_cleanup(uv_fs_t* req) {
uv__dirent_t** dents;

dents = req->ptr;
if (req->nbufs > 0 && req->nbufs != (unsigned int) req->result)
req->nbufs--;
for (; req->nbufs < (unsigned int) req->result; req->nbufs++)
free(dents[req->nbufs]);
}


int uv_fs_readdir_next(uv_fs_t* req, uv_dirent_t* ent) {
uv__dirent_t** dents;
uv__dirent_t* dent;

dents = req->ptr;

/* Free previous entity */
if (req->nbufs > 0)
free(dents[req->nbufs - 1]);

/* End was already reached */
if (req->nbufs == (unsigned int) req->result) {
free(dents);
req->ptr = NULL;
return UV_EOF;
}

dent = dents[req->nbufs++];

ent->name = dent->d_name;
#ifdef HAVE_DIRENT_TYPES
switch (dent->d_type) {
case UV__DT_DIR:
ent->type = UV_DIRENT_DIR;
break;
case UV__DT_FILE:
ent->type = UV_DIRENT_FILE;
break;
case UV__DT_LINK:
ent->type = UV_DIRENT_LINK;
break;
case UV__DT_FIFO:
ent->type = UV_DIRENT_FIFO;
break;
case UV__DT_SOCKET:
ent->type = UV_DIRENT_SOCKET;
break;
case UV__DT_CHAR:
ent->type = UV_DIRENT_CHAR;
break;
case UV__DT_BLOCK:
ent->type = UV_DIRENT_BLOCK;
break;
default:
ent->type = UV_DIRENT_UNKNOWN;
}
#else
ent->type = UV_DIRENT_UNKNOWN;
#endif

return 0;
}
@@ -107,6 +107,10 @@ void uv__work_done(uv_async_t* handle);

size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs);

int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value);

void uv__fs_readdir_cleanup(uv_fs_t* req);

#define uv__has_active_reqs(loop) \
(QUEUE_EMPTY(&(loop)->active_reqs) == 0)

@@ -35,7 +35,7 @@
#if UV_VERSION_IS_RELEASE
# define UV_VERSION_STRING UV_VERSION_STRING_BASE
#else
# define UV_VERSION_STRING UV_VERSION_STRING_BASE "-pre"
# define UV_VERSION_STRING UV_VERSION_STRING_BASE "-" UV_VERSION_SUFFIX
#endif


@@ -36,12 +36,11 @@
#include "req-inl.h"


/* The only event loop we support right now */
static uv_loop_t uv_default_loop_;
static uv_loop_t default_loop_struct;
static uv_loop_t* default_loop_ptr;

/* uv_once intialization guards */
static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
static uv_once_t uv_default_loop_init_guard_ = UV_ONCE_INIT;


#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
@@ -138,7 +137,6 @@ int uv_loop_init(uv_loop_t* loop) {
* to zero before calling uv_update_time for the first time.
*/
loop->time = 0;
loop->last_tick_count = 0;
uv_update_time(loop);

QUEUE_INIT(&loop->wq);
@@ -181,48 +179,45 @@ int uv_loop_init(uv_loop_t* loop) {
}


static void uv_default_loop_init(void) {
/* Initialize libuv itself first */
uv__once_init();

/* Initialize the main loop */
uv_loop_init(&uv_default_loop_);
}


void uv__once_init(void) {
uv_once(&uv_init_guard_, uv_init);
}


uv_loop_t* uv_default_loop(void) {
uv_once(&uv_default_loop_init_guard_, uv_default_loop_init);
return &uv_default_loop_;
if (default_loop_ptr != NULL)
return default_loop_ptr;

if (uv_loop_init(&default_loop_struct))
return NULL;

default_loop_ptr = &default_loop_struct;
return default_loop_ptr;
}


static void uv__loop_close(uv_loop_t* loop) {
size_t i;

/* close the async handle without needeing an extra loop iteration */
assert(!loop->wq_async.async_sent);
loop->wq_async.close_cb = NULL;
uv__handle_closing(&loop->wq_async);
uv__handle_close(&loop->wq_async);

if (loop != &uv_default_loop_) {
size_t i;
for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
SOCKET sock = loop->poll_peer_sockets[i];
if (sock != 0 && sock != INVALID_SOCKET)
closesocket(sock);
}
for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
SOCKET sock = loop->poll_peer_sockets[i];
if (sock != 0 && sock != INVALID_SOCKET)
closesocket(sock);
}
/* TODO: cleanup default loop*/

uv_mutex_lock(&loop->wq_mutex);
assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
assert(!uv__has_active_reqs(loop));
uv_mutex_unlock(&loop->wq_mutex);
uv_mutex_destroy(&loop->wq_mutex);

CloseHandle(loop->iocp);
}


@@ -242,6 +237,8 @@ int uv_loop_close(uv_loop_t* loop) {
#ifndef NDEBUG
memset(loop, -1, sizeof(*loop));
#endif
if (loop == default_loop_ptr)
default_loop_ptr = NULL;

return 0;
}
@@ -265,9 +262,12 @@ uv_loop_t* uv_loop_new(void) {


void uv_loop_delete(uv_loop_t* loop) {
int err = uv_loop_close(loop);
uv_loop_t* default_loop;
int err;
default_loop = default_loop_ptr;
err = uv_loop_close(loop);
assert(err == 0);
if (loop != &uv_default_loop_)
if (loop != default_loop)
free(loop);
}

@@ -313,13 +313,17 @@ static void uv_poll(uv_loop_t* loop, DWORD timeout) {
/* Package was dequeued */
req = uv_overlapped_to_req(overlapped);
uv_insert_pending_req(loop, req);

/* Some time might have passed waiting for I/O,
* so update the loop time here.
*/
uv_update_time(loop);
} else if (GetLastError() != WAIT_TIMEOUT) {
/* Serious error */
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
} else {
/* We're sure that at least `timeout` milliseconds have expired, but
* this may not be reflected yet in the GetTickCount() return value.
* Therefore we ensure it's taken into account here.
} else if (timeout > 0) {
/* GetQueuedCompletionStatus can occasionally return a little early.
* Make sure that the desired timeout is reflected in the loop time.
*/
uv__time_forward(loop, timeout);
}
@@ -346,13 +350,17 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) {
req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
uv_insert_pending_req(loop, req);
}

/* Some time might have passed waiting for I/O,
* so update the loop time here.
*/
uv_update_time(loop);
} else if (GetLastError() != WAIT_TIMEOUT) {
/* Serious error */
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
} else if (timeout > 0) {
/* We're sure that at least `timeout` milliseconds have expired, but
* this may not be reflected yet in the GetTickCount() return value.
* Therefore we ensure it's taken into account here.
/* GetQueuedCompletionStatus can occasionally return a little early.
* Make sure that the desired timeout is reflected in the loop time.
*/
uv__time_forward(loop, timeout);
}
@@ -411,7 +419,6 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
* UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
* the check.
*/
uv_update_time(loop);
uv_process_timers(loop);
}

@@ -428,3 +435,68 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {

return r;
}


int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
uv_os_fd_t fd_out;

switch (handle->type) {
case UV_TCP:
fd_out = (uv_os_fd_t)((uv_tcp_t*) handle)->socket;
break;

case UV_NAMED_PIPE:
fd_out = ((uv_pipe_t*) handle)->handle;
break;

case UV_TTY:
fd_out = ((uv_tty_t*) handle)->handle;
break;

case UV_UDP:
fd_out = (uv_os_fd_t)((uv_udp_t*) handle)->socket;
break;

case UV_POLL:
fd_out = (uv_os_fd_t)((uv_poll_t*) handle)->socket;
break;

default:
return UV_EINVAL;
}

if (uv_is_closing(handle) || fd_out == INVALID_HANDLE_VALUE)
return UV_EBADF;

*fd = fd_out;
return 0;
}


int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
int r;
int len;
SOCKET socket;

if (handle == NULL || value == NULL)
return UV_EINVAL;

if (handle->type == UV_TCP)
socket = ((uv_tcp_t*) handle)->socket;
else if (handle->type == UV_UDP)
socket = ((uv_udp_t*) handle)->socket;
else
return UV_ENOTSUP;

len = sizeof(*value);

if (*value == 0)
r = getsockopt(socket, SOL_SOCKET, optname, (char*) value, &len);
else
r = setsockopt(socket, SOL_SOCKET, optname, (const char*) value, len);

if (r == SOCKET_ERROR)
return uv_translate_sys_error(WSAGetLastError());

return 0;
}