mirror of https://github.com/grpc/grpc.git
Move eventmanager and platform dependent endpoint functionality into a single library called 'iomgr'. This is primarily to prepare for a Windows port - where posix socket semantics lead to poor quality code. Mostly this is a code movement CL, with some small changes to help prepare the way for porting: - em style fd objects can only be held internally in iomgr, and own their memory - added grpc_iomgr_create_endpoint_pair() to accomodate the common pattern of creating a tcp endpoint from the output of socketpair - this will help keep our tests portable - separated em alarm interface into a separate file, as this part of event manager is needed higher up the stack - made the eventmanager bits a true singleton, simplifying API's across the stack as there's no longer a reason to carry a pointer there. Initial design document is here: https://docs.google.com/document/d/1VmafcHvvrP5kwtQkz84R5yXF7u7fW-9Pn0bkSUQHDt8/edit?disco=AAAAARNByxg Change on 2014/12/09 by ctiller <ctiller@google.com> ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=81716456pull/1/merge
parent
98bffb779b
commit
18b49ab914
64 changed files with 1953 additions and 1998 deletions
@ -1,344 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __GRPC_INTERNAL_EVENTMANAGER_EM_H__ |
||||
#define __GRPC_INTERNAL_EVENTMANAGER_EM_H__ |
||||
/* grpc_em is an event manager wrapping event loop with multithread support.
|
||||
It executes a callback function when a specific event occurs on a file |
||||
descriptor or after a timeout has passed. |
||||
All methods are threadsafe and can be called from any thread. |
||||
|
||||
To use the event manager, a grpc_em instance needs to be initialized to |
||||
maintains the internal states. The grpc_em instance can be used to |
||||
initialize file descriptor instance of grpc_em_fd, or alarm instance of |
||||
grpc_em_alarm. The former is used to register a callback with a IO event. |
||||
The later is used to schedule an alarm. |
||||
|
||||
Instantiating any of these data structures requires including em_internal.h |
||||
A typical usage example is shown in the end of that header file. */ |
||||
|
||||
#include <grpc/support/atm.h> |
||||
#include <grpc/support/sync.h> |
||||
#include <grpc/support/thd.h> |
||||
#include <grpc/support/time.h> |
||||
|
||||
/* =============== Enums used in GRPC event manager API ==================== */ |
||||
|
||||
/* Result of a grpc_em operation */ |
||||
typedef enum grpc_em_error { |
||||
GRPC_EM_OK = 0, /* everything went ok */ |
||||
GRPC_EM_ERROR, /* internal errors not caused by the caller */ |
||||
GRPC_EM_INVALID_ARGUMENTS /* invalid arguments from the caller */ |
||||
} grpc_em_error; |
||||
|
||||
/* Status passed to callbacks for grpc_em_fd_notify_on_read and
|
||||
grpc_em_fd_notify_on_write. */ |
||||
typedef enum grpc_em_cb_status { |
||||
GRPC_CALLBACK_SUCCESS = 0, |
||||
GRPC_CALLBACK_TIMED_OUT, |
||||
GRPC_CALLBACK_CANCELLED, |
||||
GRPC_CALLBACK_DO_NOT_USE |
||||
} grpc_em_cb_status; |
||||
|
||||
/* ======= Useful forward struct typedefs for GRPC event manager API ======= */ |
||||
|
||||
struct grpc_em; |
||||
struct grpc_em_alarm; |
||||
struct grpc_fd; |
||||
|
||||
typedef struct grpc_em grpc_em; |
||||
typedef struct grpc_em_alarm grpc_em_alarm; |
||||
typedef struct grpc_em_fd grpc_em_fd; |
||||
|
||||
/* gRPC Callback definition */ |
||||
typedef void (*grpc_em_cb_func)(void *arg, grpc_em_cb_status status); |
||||
|
||||
/* ============================ grpc_em =============================== */ |
||||
/* Initialize *em and start polling, return GRPC_EM_OK on success, return
|
||||
GRPC_EM_ERROR on failure. Upon failure, caller should call grpc_em_destroy() |
||||
to clean partially initialized *em. |
||||
|
||||
Requires: *em uninitialized. */ |
||||
grpc_em_error grpc_em_init(grpc_em *em); |
||||
|
||||
/* Stop polling and cause *em no longer to be initialized.
|
||||
Return GRPC_EM_OK if event polling is cleanly stopped. |
||||
Otherwise, return GRPC_EM_ERROR if polling is shutdown with errors. |
||||
Requires: *em initialized; no other concurrent operation on *em. */ |
||||
grpc_em_error grpc_em_destroy(grpc_em *em); |
||||
|
||||
/* do some work; assumes em->mu locked; may unlock and relock em->mu */ |
||||
int grpc_em_work(grpc_em *em, gpr_timespec deadline); |
||||
|
||||
/* =========================== grpc_em_am ============================== */ |
||||
/* Initialize *alarm. When expired or canceled, alarm_cb will be called with
|
||||
*alarm_cb_arg and status to indicate if it expired (SUCCESS) or was |
||||
canceled (CANCELLED). alarm_cb is guaranteed to be called exactly once, |
||||
and application code should check the status to determine how it was |
||||
invoked. The application callback is also responsible for maintaining |
||||
information about when to free up any user-level state. */ |
||||
grpc_em_error grpc_em_alarm_init(grpc_em_alarm *alarm, grpc_em *em, |
||||
grpc_em_cb_func alarm_cb, void *alarm_cb_arg); |
||||
|
||||
/* Note that there is no alarm destroy function. This is because the
|
||||
alarm is a one-time occurrence with a guarantee that the callback will |
||||
be called exactly once, either at expiration or cancellation. Thus, all |
||||
the internal alarm event management state is destroyed just before |
||||
that callback is invoked. If the user has additional state associated with |
||||
the alarm, the user is responsible for determining when it is safe to |
||||
destroy that state. */ |
||||
|
||||
/* Schedule *alarm to expire at deadline. If *alarm is
|
||||
re-added before expiration, the *delay is simply reset to the new value. |
||||
Return GRPC_EM_OK on success, or GRPC_EM_ERROR on failure. |
||||
Upon failure, caller should abort further operations on *alarm */ |
||||
grpc_em_error grpc_em_alarm_add(grpc_em_alarm *alarm, gpr_timespec deadline); |
||||
|
||||
/* Cancel an *alarm.
|
||||
There are three cases: |
||||
1. We normally cancel the alarm |
||||
2. The alarm has already run |
||||
3. We can't cancel the alarm because it is "in flight". |
||||
|
||||
In all of these cases, the cancellation is still considered successful. |
||||
They are essentially distinguished in that the alarm_cb will be run |
||||
exactly once from either the cancellation (with status CANCELLED) |
||||
or from the activation (with status SUCCESS) |
||||
|
||||
Requires: cancel() must happen after add() on a given alarm */ |
||||
grpc_em_error grpc_em_alarm_cancel(grpc_em_alarm *alarm); |
||||
|
||||
/* ========================== grpc_em_fd ============================= */ |
||||
|
||||
/* Initialize *em_fd, return GRPM_EM_OK on success, GRPC_EM_ERROR on internal
|
||||
errors, or GRPC_EM_INVALID_ARGUMENTS if fd is a blocking file descriptor. |
||||
Upon failure, caller should call grpc_em_fd_destroy() to clean partially |
||||
initialized *em_fd. |
||||
fd is a non-blocking file descriptor. |
||||
|
||||
This takes ownership of closing fd. |
||||
|
||||
Requires: *em_fd uninitialized. fd is a non-blocking file descriptor. */ |
||||
grpc_em_error grpc_em_fd_init(grpc_em_fd *em_fd, grpc_em *em, int fd); |
||||
|
||||
/* Cause *em_fd no longer to be initialized and closes the underlying fd.
|
||||
Requires: *em_fd initialized; no outstanding notify_on_read or |
||||
notify_on_write. */ |
||||
void grpc_em_fd_destroy(grpc_em_fd *em_fd); |
||||
|
||||
/* Returns the file descriptor associated with *em_fd. */ |
||||
int grpc_em_fd_get(grpc_em_fd *em_fd); |
||||
|
||||
/* Returns the event manager associated with *em_fd. */ |
||||
grpc_em *grpc_em_fd_get_em(grpc_em_fd *em_fd); |
||||
|
||||
/* Register read interest, causing read_cb to be called once when em_fd becomes
|
||||
readable, on deadline specified by deadline, or on shutdown triggered by |
||||
grpc_em_fd_shutdown. |
||||
Return GRPC_EM_OK on success, or GRPC_EM_ERROR on failure. |
||||
Upon Failure, caller should abort further operations on *em_fd except |
||||
grpc_em_fd_shutdown(). |
||||
read_cb will be called with read_cb_arg when *em_fd becomes readable. |
||||
read_cb is Called with status of GRPC_CALLBACK_SUCCESS if readable, |
||||
GRPC_CALLBACK_TIMED_OUT if the call timed out, |
||||
and CANCELLED if the call was cancelled. |
||||
|
||||
Requires:This method must not be called before the read_cb for any previous |
||||
call runs. Edge triggered events are used whenever they are supported by the |
||||
underlying platform. This means that users must drain em_fd in read_cb before |
||||
calling notify_on_read again. Users are also expected to handle spurious |
||||
events, i.e read_cb is called while nothing can be readable from em_fd */ |
||||
grpc_em_error grpc_em_fd_notify_on_read(grpc_em_fd *em_fd, |
||||
grpc_em_cb_func read_cb, |
||||
void *read_cb_arg, |
||||
gpr_timespec deadline); |
||||
|
||||
/* Exactly the same semantics as above, except based on writable events. */ |
||||
grpc_em_error grpc_em_fd_notify_on_write(grpc_em_fd *fd, |
||||
grpc_em_cb_func write_cb, |
||||
void *write_cb_arg, |
||||
gpr_timespec deadline); |
||||
|
||||
/* Cause any current and all future read/write callbacks to error out with
|
||||
GRPC_CALLBACK_CANCELLED. */ |
||||
void grpc_em_fd_shutdown(grpc_em_fd *em_fd); |
||||
|
||||
/* ================== Other functions =================== */ |
||||
|
||||
/* This function is called from within a callback or from anywhere else
|
||||
and causes the invocation of a callback at some point in the future */ |
||||
grpc_em_error grpc_em_add_callback(grpc_em *em, grpc_em_cb_func cb, |
||||
void *cb_arg); |
||||
|
||||
/* ========== Declarations related to queue management (non-API) =========== */ |
||||
|
||||
/* Forward declarations */ |
||||
struct grpc_em_activation_data; |
||||
struct grpc_em_fd_impl; |
||||
|
||||
/* ================== Actual structure definitions ========================= */ |
||||
/* gRPC event manager handle.
|
||||
The handle is used to initialize both grpc_em_alarm and grpc_em_fd. */ |
||||
struct em_thread_arg; |
||||
|
||||
struct grpc_em { |
||||
struct event_base *event_base; |
||||
|
||||
gpr_mu mu; |
||||
gpr_cv cv; |
||||
struct grpc_em_activation_data *q; |
||||
int num_pollers; |
||||
int num_fds; |
||||
gpr_timespec last_poll_completed; |
||||
|
||||
int shutdown_backup_poller; |
||||
gpr_event backup_poller_done; |
||||
|
||||
struct grpc_em_fd_impl *fds_to_free; |
||||
|
||||
struct event *timeout_ev; /* activated to break out of the event loop early */ |
||||
}; |
||||
|
||||
/* gRPC event manager task "base class". This is pretend-inheritance in C89.
|
||||
This should be the first member of any actual grpc_em task type. |
||||
|
||||
Memory warning: expanding this will increase memory usage in any derived |
||||
class, so be careful. |
||||
|
||||
For generality, this base can be on multiple task queues and can have |
||||
multiple event callbacks registered. Not all "derived classes" will use |
||||
this feature. */ |
||||
|
||||
typedef enum grpc_em_task_type { |
||||
GRPC_EM_TASK_ALARM, |
||||
GRPC_EM_TASK_FD, |
||||
GRPC_EM_TASK_DO_NOT_USE |
||||
} grpc_em_task_type; |
||||
|
||||
/* Different activity types to shape the callback and queueing arrays */ |
||||
typedef enum grpc_em_task_activity_type { |
||||
GRPC_EM_TA_READ, /* use this also for single-type events */ |
||||
GRPC_EM_TA_WRITE, |
||||
GRPC_EM_TA_COUNT |
||||
} grpc_em_task_activity_type; |
||||
|
||||
/* Include the following #define for convenience for tasks like alarms that
|
||||
only have a single type */ |
||||
#define GRPC_EM_TA_ONLY GRPC_EM_TA_READ |
||||
|
||||
typedef struct grpc_em_activation_data { |
||||
struct event *ev; /* event activated on this callback type */ |
||||
grpc_em_cb_func cb; /* function pointer for callback */ |
||||
void *arg; /* argument passed to cb */ |
||||
|
||||
/* Hold the status associated with the callback when queued */ |
||||
grpc_em_cb_status status; |
||||
/* Now set up to link activations into scheduler queues */ |
||||
struct grpc_em_activation_data *prev; |
||||
struct grpc_em_activation_data *next; |
||||
} grpc_em_activation_data; |
||||
|
||||
typedef struct grpc_em_task { |
||||
grpc_em_task_type type; |
||||
grpc_em *em; |
||||
|
||||
/* Now have an array of activation data elements: one for each activity
|
||||
type that could get activated */ |
||||
grpc_em_activation_data activation[GRPC_EM_TA_COUNT]; |
||||
} grpc_em_task; |
||||
|
||||
/* gRPC alarm handle.
|
||||
The handle is used to add an alarm which expires after specified timeout. */ |
||||
struct grpc_em_alarm { |
||||
grpc_em_task task; /* Include the base class */ |
||||
|
||||
gpr_atm triggered; /* To be used atomically if alarm triggered */ |
||||
}; |
||||
|
||||
/* =================== Event caching ===================
|
||||
In order to not miss or double-return edges in the context of edge triggering |
||||
and multithreading, we need a per-fd caching layer in the eventmanager itself |
||||
to cache relevant events. |
||||
|
||||
There are two types of events we care about: calls to notify_on_[read|write] |
||||
and readable/writable events for the socket from eventfd. There are separate |
||||
event caches for read and write. |
||||
|
||||
There are three states: |
||||
0. "waiting" -- There's been a call to notify_on_[read|write] which has not |
||||
had a corresponding event. In other words, we're waiting for an event so we |
||||
can run the callback. |
||||
1. "idle" -- We are neither waiting nor have a cached event. |
||||
2. "cached" -- There has been a read/write event without a waiting callback, |
||||
so we want to run the event next time the application calls |
||||
notify_on_[read|write]. |
||||
|
||||
The high level state diagram: |
||||
|
||||
+--------------------------------------------------------------------+ |
||||
| WAITING | IDLE | CACHED | |
||||
| | | | |
||||
| 1. --*-> 2. --+-> 3. --+\
|
||||
| | | <--+/ |
||||
| | | | |
||||
x+-- 6. 5. <-+-- 4. <-*-- | |
||||
| | | | |
||||
+--------------------------------------------------------------------+ |
||||
|
||||
Transitions right occur on read|write events. Transitions left occur on |
||||
notify_on_[read|write] events. |
||||
State transitions: |
||||
1. Read|Write event while waiting -> run the callback and transition to idle. |
||||
2. Read|Write event while idle -> transition to cached. |
||||
3. Read|Write event with one already cached -> still cached. |
||||
4. notify_on_[read|write] with event cached: run callback and transition to |
||||
idle. |
||||
5. notify_on_[read|write] when idle: Store callback and transition to |
||||
waiting. |
||||
6. notify_on_[read|write] when waiting: invalid. */ |
||||
|
||||
typedef enum grpc_em_fd_state { |
||||
GRPC_EM_FD_WAITING = 0, |
||||
GRPC_EM_FD_IDLE = 1, |
||||
GRPC_EM_FD_CACHED = 2 |
||||
} grpc_em_fd_state; |
||||
|
||||
struct grpc_em_fd_impl; |
||||
|
||||
/* gRPC file descriptor handle.
|
||||
The handle is used to register read/write callbacks to a file descriptor */ |
||||
struct grpc_em_fd { |
||||
struct grpc_em_fd_impl *impl; |
||||
}; |
||||
|
||||
#endif /* __GRPC_INTERNAL_EVENTMANAGER_EM_H__ */ |
@ -0,0 +1,85 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __GRPC_INTERNAL_IOMGR_ALARM_H__ |
||||
#define __GRPC_INTERNAL_IOMGR_ALARM_H__ |
||||
|
||||
#include "src/core/iomgr/iomgr.h" |
||||
#include <grpc/support/port_platform.h> |
||||
#include <grpc/support/time.h> |
||||
|
||||
typedef struct grpc_alarm grpc_alarm; |
||||
|
||||
/* One of the following headers should provide struct grpc_alarm */ |
||||
#ifdef GPR_LIBEVENT |
||||
#include "src/core/iomgr/iomgr_libevent.h" |
||||
#endif |
||||
|
||||
/* Initialize *alarm. When expired or canceled, alarm_cb will be called with
|
||||
*alarm_cb_arg and status to indicate if it expired (SUCCESS) or was |
||||
canceled (CANCELLED). alarm_cb is guaranteed to be called exactly once, |
||||
and application code should check the status to determine how it was |
||||
invoked. The application callback is also responsible for maintaining |
||||
information about when to free up any user-level state. */ |
||||
void grpc_alarm_init(grpc_alarm *alarm, grpc_iomgr_cb_func alarm_cb, |
||||
void *alarm_cb_arg); |
||||
|
||||
/* Note that there is no alarm destroy function. This is because the
|
||||
alarm is a one-time occurrence with a guarantee that the callback will |
||||
be called exactly once, either at expiration or cancellation. Thus, all |
||||
the internal alarm event management state is destroyed just before |
||||
that callback is invoked. If the user has additional state associated with |
||||
the alarm, the user is responsible for determining when it is safe to |
||||
destroy that state. */ |
||||
|
||||
/* Schedule *alarm to expire at deadline. If *alarm is
|
||||
re-added before expiration, the *delay is simply reset to the new value. |
||||
Return GRPC_EM_OK on success, or GRPC_EM_ERROR on failure. |
||||
Upon failure, caller should abort further operations on *alarm */ |
||||
int grpc_alarm_add(grpc_alarm *alarm, gpr_timespec deadline); |
||||
|
||||
/* Cancel an *alarm.
|
||||
There are three cases: |
||||
1. We normally cancel the alarm |
||||
2. The alarm has already run |
||||
3. We can't cancel the alarm because it is "in flight". |
||||
|
||||
In all of these cases, the cancellation is still considered successful. |
||||
They are essentially distinguished in that the alarm_cb will be run |
||||
exactly once from either the cancellation (with status CANCELLED) |
||||
or from the activation (with status SUCCESS) |
||||
|
||||
Requires: cancel() must happen after add() on a given alarm */ |
||||
int grpc_alarm_cancel(grpc_alarm *alarm); |
||||
|
||||
#endif /* __GRPC_INTERNAL_IOMGR_ALARM_H__ */ |
@ -0,0 +1,61 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/iomgr/endpoint_pair.h" |
||||
|
||||
#include <errno.h> |
||||
#include <fcntl.h> |
||||
#include <string.h> |
||||
#include <sys/types.h> |
||||
#include <sys/socket.h> |
||||
|
||||
#include "src/core/iomgr/tcp_posix.h" |
||||
#include <grpc/support/log.h> |
||||
|
||||
static void create_sockets(int sv[2]) { |
||||
int flags; |
||||
GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0); |
||||
flags = fcntl(sv[0], F_GETFL, 0); |
||||
GPR_ASSERT(fcntl(sv[0], F_SETFL, flags | O_NONBLOCK) == 0); |
||||
flags = fcntl(sv[1], F_GETFL, 0); |
||||
GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0); |
||||
} |
||||
|
||||
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(size_t read_slice_size) { |
||||
int sv[2]; |
||||
grpc_endpoint_pair p; |
||||
create_sockets(sv); |
||||
p.client = grpc_tcp_create(grpc_fd_create(sv[1]), read_slice_size); |
||||
p.server = grpc_tcp_create(grpc_fd_create(sv[0]), read_slice_size); |
||||
return p; |
||||
} |
@ -0,0 +1,56 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __GRPC_INTERNAL_IOMGR_IOMGR_H__ |
||||
#define __GRPC_INTERNAL_IOMGR_IOMGR_H__ |
||||
|
||||
/* Status passed to callbacks for grpc_em_fd_notify_on_read and
|
||||
grpc_em_fd_notify_on_write. */ |
||||
typedef enum grpc_em_cb_status { |
||||
GRPC_CALLBACK_SUCCESS = 0, |
||||
GRPC_CALLBACK_TIMED_OUT, |
||||
GRPC_CALLBACK_CANCELLED, |
||||
GRPC_CALLBACK_DO_NOT_USE |
||||
} grpc_iomgr_cb_status; |
||||
|
||||
/* gRPC Callback definition */ |
||||
typedef void (*grpc_iomgr_cb_func)(void *arg, grpc_iomgr_cb_status status); |
||||
|
||||
void grpc_iomgr_init(); |
||||
void grpc_iomgr_shutdown(); |
||||
|
||||
/* This function is called from within a callback or from anywhere else
|
||||
and causes the invocation of a callback at some point in the future */ |
||||
void grpc_iomgr_add_callback(grpc_iomgr_cb_func cb, void *cb_arg); |
||||
|
||||
#endif /* __GRPC_INTERNAL_IOMGR_IOMGR_H__ */ |
@ -0,0 +1,207 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __GRPC_INTERNAL_IOMGR_IOMGR_LIBEVENT_H__ |
||||
#define __GRPC_INTERNAL_IOMGR_IOMGR_LIBEVENT_H__ |
||||
|
||||
#include "src/core/iomgr/iomgr.h" |
||||
#include <grpc/support/sync.h> |
||||
#include <grpc/support/time.h> |
||||
|
||||
typedef struct grpc_fd grpc_fd; |
||||
|
||||
/* gRPC event manager task "base class". This is pretend-inheritance in C89.
|
||||
This should be the first member of any actual grpc_em task type. |
||||
|
||||
Memory warning: expanding this will increase memory usage in any derived |
||||
class, so be careful. |
||||
|
||||
For generality, this base can be on multiple task queues and can have |
||||
multiple event callbacks registered. Not all "derived classes" will use |
||||
this feature. */ |
||||
|
||||
typedef enum grpc_libevent_task_type { |
||||
GRPC_EM_TASK_ALARM, |
||||
GRPC_EM_TASK_FD, |
||||
GRPC_EM_TASK_DO_NOT_USE |
||||
} grpc_libevent_task_type; |
||||
|
||||
/* Different activity types to shape the callback and queueing arrays */ |
||||
typedef enum grpc_em_task_activity_type { |
||||
GRPC_EM_TA_READ, /* use this also for single-type events */ |
||||
GRPC_EM_TA_WRITE, |
||||
GRPC_EM_TA_COUNT |
||||
} grpc_em_task_activity_type; |
||||
|
||||
/* Include the following #define for convenience for tasks like alarms that
|
||||
only have a single type */ |
||||
#define GRPC_EM_TA_ONLY GRPC_EM_TA_READ |
||||
|
||||
typedef struct grpc_libevent_activation_data { |
||||
struct event *ev; /* event activated on this callback type */ |
||||
grpc_iomgr_cb_func cb; /* function pointer for callback */ |
||||
void *arg; /* argument passed to cb */ |
||||
|
||||
/* Hold the status associated with the callback when queued */ |
||||
grpc_iomgr_cb_status status; |
||||
/* Now set up to link activations into scheduler queues */ |
||||
struct grpc_libevent_activation_data *prev; |
||||
struct grpc_libevent_activation_data *next; |
||||
} grpc_libevent_activation_data; |
||||
|
||||
typedef struct grpc_libevent_task { |
||||
grpc_libevent_task_type type; |
||||
|
||||
/* Now have an array of activation data elements: one for each activity
|
||||
type that could get activated */ |
||||
grpc_libevent_activation_data activation[GRPC_EM_TA_COUNT]; |
||||
} grpc_libevent_task; |
||||
|
||||
/* Initialize *em_fd.
|
||||
Requires fd is a non-blocking file descriptor. |
||||
|
||||
This takes ownership of closing fd. |
||||
|
||||
Requires: *em_fd uninitialized. fd is a non-blocking file descriptor. */ |
||||
grpc_fd *grpc_fd_create(int fd); |
||||
|
||||
/* Cause *em_fd no longer to be initialized and closes the underlying fd.
|
||||
Requires: *em_fd initialized; no outstanding notify_on_read or |
||||
notify_on_write. */ |
||||
void grpc_fd_destroy(grpc_fd *em_fd); |
||||
|
||||
/* Returns the file descriptor associated with *em_fd. */ |
||||
int grpc_fd_get(grpc_fd *em_fd); |
||||
|
||||
/* Register read interest, causing read_cb to be called once when em_fd becomes
|
||||
readable, on deadline specified by deadline, or on shutdown triggered by |
||||
grpc_fd_shutdown. |
||||
read_cb will be called with read_cb_arg when *em_fd becomes readable. |
||||
read_cb is Called with status of GRPC_CALLBACK_SUCCESS if readable, |
||||
GRPC_CALLBACK_TIMED_OUT if the call timed out, |
||||
and CANCELLED if the call was cancelled. |
||||
|
||||
Requires:This method must not be called before the read_cb for any previous |
||||
call runs. Edge triggered events are used whenever they are supported by the |
||||
underlying platform. This means that users must drain em_fd in read_cb before |
||||
calling notify_on_read again. Users are also expected to handle spurious |
||||
events, i.e read_cb is called while nothing can be readable from em_fd */ |
||||
int grpc_fd_notify_on_read(grpc_fd *em_fd, grpc_iomgr_cb_func read_cb, |
||||
void *read_cb_arg, gpr_timespec deadline); |
||||
|
||||
/* Exactly the same semantics as above, except based on writable events. */ |
||||
int grpc_fd_notify_on_write(grpc_fd *fd, grpc_iomgr_cb_func write_cb, |
||||
void *write_cb_arg, gpr_timespec deadline); |
||||
|
||||
/* Cause any current and all future read/write callbacks to error out with
|
||||
GRPC_CALLBACK_CANCELLED. */ |
||||
void grpc_fd_shutdown(grpc_fd *em_fd); |
||||
|
||||
/* =================== Event caching ===================
|
||||
In order to not miss or double-return edges in the context of edge triggering |
||||
and multithreading, we need a per-fd caching layer in the eventmanager itself |
||||
to cache relevant events. |
||||
|
||||
There are two types of events we care about: calls to notify_on_[read|write] |
||||
and readable/writable events for the socket from eventfd. There are separate |
||||
event caches for read and write. |
||||
|
||||
There are three states: |
||||
0. "waiting" -- There's been a call to notify_on_[read|write] which has not |
||||
had a corresponding event. In other words, we're waiting for an event so we |
||||
can run the callback. |
||||
1. "idle" -- We are neither waiting nor have a cached event. |
||||
2. "cached" -- There has been a read/write event without a waiting callback, |
||||
so we want to run the event next time the application calls |
||||
notify_on_[read|write]. |
||||
|
||||
The high level state diagram: |
||||
|
||||
+--------------------------------------------------------------------+ |
||||
| WAITING | IDLE | CACHED | |
||||
| | | | |
||||
| 1. --*-> 2. --+-> 3. --+\
|
||||
| | | <--+/ |
||||
| | | | |
||||
x+-- 6. 5. <-+-- 4. <-*-- | |
||||
| | | | |
||||
+--------------------------------------------------------------------+ |
||||
|
||||
Transitions right occur on read|write events. Transitions left occur on |
||||
notify_on_[read|write] events. |
||||
State transitions: |
||||
1. Read|Write event while waiting -> run the callback and transition to idle. |
||||
2. Read|Write event while idle -> transition to cached. |
||||
3. Read|Write event with one already cached -> still cached. |
||||
4. notify_on_[read|write] with event cached: run callback and transition to |
||||
idle. |
||||
5. notify_on_[read|write] when idle: Store callback and transition to |
||||
waiting. |
||||
6. notify_on_[read|write] when waiting: invalid. */ |
||||
|
||||
typedef enum grpc_fd_state { |
||||
GRPC_FD_WAITING = 0, |
||||
GRPC_FD_IDLE = 1, |
||||
GRPC_FD_CACHED = 2 |
||||
} grpc_fd_state; |
||||
|
||||
/* gRPC file descriptor handle.
|
||||
The handle is used to register read/write callbacks to a file descriptor */ |
||||
struct grpc_fd { |
||||
grpc_libevent_task task; /* Base class, callbacks, queues, etc */ |
||||
int fd; /* File descriptor */ |
||||
|
||||
/* Note that the shutdown event is only needed as a workaround for libevent
|
||||
not properly handling event_active on an in flight event. */ |
||||
struct event *shutdown_ev; /* activated to trigger shutdown */ |
||||
|
||||
/* protect shutdown_started|read_state|write_state and ensure barriers
|
||||
between notify_on_[read|write] and read|write callbacks */ |
||||
gpr_mu mu; |
||||
int shutdown_started; /* 0 -> shutdown not started, 1 -> started */ |
||||
grpc_fd_state read_state; |
||||
grpc_fd_state write_state; |
||||
|
||||
/* descriptor delete list. These are destroyed during polling. */ |
||||
struct grpc_fd *next; |
||||
}; |
||||
|
||||
/* gRPC alarm handle.
|
||||
The handle is used to add an alarm which expires after specified timeout. */ |
||||
struct grpc_alarm { |
||||
grpc_libevent_task task; /* Include the base class */ |
||||
|
||||
gpr_atm triggered; /* To be used atomically if alarm triggered */ |
||||
}; |
||||
|
||||
#endif /* __GRPC_INTERNAL_IOMGR_IOMGR_LIBEVENT_H__ */ |
@ -0,0 +1,47 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __GRPC_INTERNAL_IOMGR_SOCKADDR_H_ |
||||
#define __GRPC_INTERNAL_IOMGR_SOCKADDR_H_ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GPR_WIN32 |
||||
#include "src/core/iomgr/sockaddr_win32.h" |
||||
#endif |
||||
|
||||
#ifdef GPR_POSIX_SOCKETADDR |
||||
#include "src/core/iomgr/sockaddr_posix.h" |
||||
#endif |
||||
|
||||
#endif /* __GRPC_INTERNAL_IOMGR_SOCKADDR_H_ */ |
@ -0,0 +1,40 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __GRPC_INTERNAL_IOMGR_SOCKADDR_POSIX_H_ |
||||
#define __GRPC_INTERNAL_IOMGR_SOCKADDR_POSIX_H_ |
||||
|
||||
#include <sys/socket.h> |
||||
#include <netinet/in.h> |
||||
|
||||
#endif /* __GRPC_INTERNAL_IOMGR_SOCKADDR_POSIX_H_ */ |
@ -0,0 +1,75 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __GRPC_INTERNAL_IOMGR_SOCKADDR_UTILS_H__ |
||||
#define __GRPC_INTERNAL_IOMGR_SOCKADDR_UTILS_H__ |
||||
|
||||
#include "src/core/iomgr/sockaddr.h" |
||||
|
||||
/* Returns true if addr is an IPv4-mapped IPv6 address within the
|
||||
::ffff:0.0.0.0/96 range, or false otherwise. |
||||
|
||||
If addr4_out is non-NULL, the inner IPv4 address will be copied here when |
||||
returning true. */ |
||||
int grpc_sockaddr_is_v4mapped(const struct sockaddr *addr, |
||||
struct sockaddr_in *addr4_out); |
||||
|
||||
/* If addr is an AF_INET address, writes the corresponding ::ffff:0.0.0.0/96
|
||||
address to addr6_out and returns true. Otherwise returns false. */ |
||||
int grpc_sockaddr_to_v4mapped(const struct sockaddr *addr, |
||||
struct sockaddr_in6 *addr6_out); |
||||
|
||||
/* If addr is ::, 0.0.0.0, or ::ffff:0.0.0.0, writes the port number to
|
||||
*port_out (if not NULL) and returns true, otherwise returns false. */ |
||||
int grpc_sockaddr_is_wildcard(const struct sockaddr *addr, int *port_out); |
||||
|
||||
/* Writes 0.0.0.0:port and [::]:port to separate sockaddrs. */ |
||||
void grpc_sockaddr_make_wildcards(int port, struct sockaddr_in *wild4_out, |
||||
struct sockaddr_in6 *wild6_out); |
||||
|
||||
/* Converts a sockaddr into a newly-allocated human-readable string.
|
||||
|
||||
Currently, only the AF_INET and AF_INET6 families are recognized. |
||||
If the normalize flag is enabled, ::ffff:0.0.0.0/96 IPv6 addresses are |
||||
displayed as plain IPv4. |
||||
|
||||
Usage is similar to gpr_asprintf: returns the number of bytes written |
||||
(excluding the final '\0'), and *out points to a string which must later be |
||||
destroyed using gpr_free(). |
||||
|
||||
In the unlikely event of an error, returns -1 and sets *out to NULL. |
||||
The existing value of errno is always preserved. */ |
||||
int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr, |
||||
int normalize); |
||||
|
||||
#endif /* __GRPC_INTERNAL_IOMGR_SOCKADDR_UTILS_H__ */ |
@ -0,0 +1,154 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/iomgr/socket_utils_posix.h" |
||||
|
||||
#include <arpa/inet.h> |
||||
#include <limits.h> |
||||
#include <fcntl.h> |
||||
#include <netinet/in.h> |
||||
#include <netinet/tcp.h> |
||||
#include <stdio.h> |
||||
#include <sys/types.h> |
||||
#include <sys/socket.h> |
||||
#include <unistd.h> |
||||
#include <string.h> |
||||
#include <errno.h> |
||||
|
||||
#include "src/core/iomgr/sockaddr_utils.h" |
||||
#include <grpc/support/host_port.h> |
||||
#include <grpc/support/string.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
/* set a socket to non blocking mode */ |
||||
int grpc_set_socket_nonblocking(int fd, int non_blocking) { |
||||
int oldflags = fcntl(fd, F_GETFL, 0); |
||||
if (oldflags < 0) { |
||||
return 0; |
||||
} |
||||
|
||||
if (non_blocking) { |
||||
oldflags |= O_NONBLOCK; |
||||
} else { |
||||
oldflags &= ~O_NONBLOCK; |
||||
} |
||||
|
||||
if (fcntl(fd, F_SETFL, oldflags) != 0) { |
||||
return 0; |
||||
} |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
/* set a socket to close on exec */ |
||||
int grpc_set_socket_cloexec(int fd, int close_on_exec) { |
||||
int oldflags = fcntl(fd, F_GETFD, 0); |
||||
if (oldflags < 0) { |
||||
return 0; |
||||
} |
||||
|
||||
if (close_on_exec) { |
||||
oldflags |= FD_CLOEXEC; |
||||
} else { |
||||
oldflags &= ~FD_CLOEXEC; |
||||
} |
||||
|
||||
if (fcntl(fd, F_SETFD, oldflags) != 0) { |
||||
return 0; |
||||
} |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
/* set a socket to reuse old addresses */ |
||||
int grpc_set_socket_reuse_addr(int fd, int reuse) { |
||||
int val = (reuse != 0); |
||||
int newval; |
||||
socklen_t intlen = sizeof(newval); |
||||
return 0 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) && |
||||
0 == getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &newval, &intlen) && |
||||
newval == val; |
||||
} |
||||
|
||||
/* disable nagle */ |
||||
int grpc_set_socket_low_latency(int fd, int low_latency) { |
||||
int val = (low_latency != 0); |
||||
int newval; |
||||
socklen_t intlen = sizeof(newval); |
||||
return 0 == setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) && |
||||
0 == getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &newval, &intlen) && |
||||
newval == val; |
||||
} |
||||
|
||||
/* This should be 0 in production, but it may be enabled for testing or
|
||||
debugging purposes, to simulate an environment where IPv6 sockets can't |
||||
also speak IPv4. */ |
||||
int grpc_forbid_dualstack_sockets_for_testing = 0; |
||||
|
||||
static int set_socket_dualstack(int fd) { |
||||
if (!grpc_forbid_dualstack_sockets_for_testing) { |
||||
const int off = 0; |
||||
return 0 == setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off)); |
||||
} else { |
||||
/* Force an IPv6-only socket, for testing purposes. */ |
||||
const int on = 1; |
||||
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
int grpc_create_dualstack_socket(const struct sockaddr *addr, int type, |
||||
int protocol, grpc_dualstack_mode *dsmode) { |
||||
int family = addr->sa_family; |
||||
if (family == AF_INET6) { |
||||
int fd = socket(family, type, protocol); |
||||
/* Check if we've got a valid dualstack socket. */ |
||||
if (fd >= 0 && set_socket_dualstack(fd)) { |
||||
*dsmode = GRPC_DSMODE_DUALSTACK; |
||||
return fd; |
||||
} |
||||
/* If this isn't an IPv4 address, then return whatever we've got. */ |
||||
if (!grpc_sockaddr_is_v4mapped(addr, NULL)) { |
||||
*dsmode = GRPC_DSMODE_IPV6; |
||||
return fd; |
||||
} |
||||
/* Fall back to AF_INET. */ |
||||
if (fd >= 0) { |
||||
close(fd); |
||||
} |
||||
family = AF_INET; |
||||
} |
||||
*dsmode = family == AF_INET ? GRPC_DSMODE_IPV4 : GRPC_DSMODE_NONE; |
||||
return socket(family, type, protocol); |
||||
} |
@ -1,198 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
/* Test grpc_em_fd with pipe. The test creates a pipe with non-blocking mode,
|
||||
sends a stream of bytes through the pipe, and verifies that all bytes are |
||||
received. */ |
||||
#include "src/core/eventmanager/em.h" |
||||
|
||||
#include <errno.h> |
||||
#include <fcntl.h> |
||||
#include <pthread.h> |
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
#include <unistd.h> |
||||
|
||||
#include <grpc/support/log.h> |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
/* Operation for fcntl() to set pipe buffer size. */ |
||||
#ifndef F_SETPIPE_SZ |
||||
#define F_SETPIPE_SZ (1024 + 7) |
||||
#endif |
||||
|
||||
#define TOTAL_WRITE 3 /* total number of times that the write buffer is full. \ |
||||
*/ |
||||
#define BUF_SIZE 1024 |
||||
char read_buf[BUF_SIZE]; |
||||
char write_buf[BUF_SIZE]; |
||||
|
||||
typedef struct { |
||||
int fd[2]; |
||||
grpc_em em; |
||||
grpc_em_fd read_em_fd; |
||||
grpc_em_fd write_em_fd; |
||||
int num_write; /* number of times that the write buffer is full*/ |
||||
ssize_t bytes_written_total; /* total number of bytes written to the pipe */ |
||||
ssize_t bytes_read_total; /* total number of bytes read from the pipe */ |
||||
pthread_mutex_t mu; /* protect cv and done */ |
||||
pthread_cond_t cv; /* signaled when read finished */ |
||||
int done; /* set to 1 when read finished */ |
||||
} async_pipe; |
||||
|
||||
void write_shutdown_cb(void *arg, /*async_pipe*/ |
||||
enum grpc_em_cb_status status) { |
||||
async_pipe *ap = arg; |
||||
grpc_em_fd_destroy(&ap->write_em_fd); |
||||
} |
||||
|
||||
void write_cb(void *arg, /*async_pipe*/ enum grpc_em_cb_status status) { |
||||
async_pipe *ap = arg; |
||||
ssize_t bytes_written = 0; |
||||
|
||||
if (status == GRPC_CALLBACK_CANCELLED) { |
||||
write_shutdown_cb(arg, GRPC_CALLBACK_SUCCESS); |
||||
return; |
||||
} |
||||
|
||||
do { |
||||
bytes_written = write(ap->fd[1], write_buf, BUF_SIZE); |
||||
if (bytes_written > 0) ap->bytes_written_total += bytes_written; |
||||
} while (bytes_written > 0); |
||||
|
||||
if (errno == EAGAIN) { |
||||
if (ap->num_write < TOTAL_WRITE) { |
||||
ap->num_write++; |
||||
grpc_em_fd_notify_on_write(&ap->write_em_fd, write_cb, ap, |
||||
gpr_inf_future); |
||||
} else { |
||||
/* Note that this could just shut down directly; doing a trip through the
|
||||
shutdown path serves only a demonstration of the API. */ |
||||
grpc_em_fd_shutdown(&ap->write_em_fd); |
||||
grpc_em_fd_notify_on_write(&ap->write_em_fd, write_cb, ap, |
||||
gpr_inf_future); |
||||
} |
||||
} else { |
||||
GPR_ASSERT(0 && strcat("unknown errno: ", strerror(errno))); |
||||
} |
||||
} |
||||
|
||||
void read_shutdown_cb(void *arg, /*async_pipe*/ enum grpc_em_cb_status status) { |
||||
async_pipe *ap = arg; |
||||
grpc_em_fd_destroy(&ap->read_em_fd); |
||||
pthread_mutex_lock(&ap->mu); |
||||
if (ap->done == 0) { |
||||
ap->done = 1; |
||||
pthread_cond_signal(&ap->cv); |
||||
} |
||||
pthread_mutex_unlock(&ap->mu); |
||||
} |
||||
|
||||
void read_cb(void *arg, /*async_pipe*/ enum grpc_em_cb_status status) { |
||||
async_pipe *ap = arg; |
||||
ssize_t bytes_read = 0; |
||||
|
||||
if (status == GRPC_CALLBACK_CANCELLED) { |
||||
read_shutdown_cb(arg, GRPC_CALLBACK_SUCCESS); |
||||
return; |
||||
} |
||||
|
||||
do { |
||||
bytes_read = read(ap->fd[0], read_buf, BUF_SIZE); |
||||
if (bytes_read > 0) ap->bytes_read_total += bytes_read; |
||||
} while (bytes_read > 0); |
||||
|
||||
if (bytes_read == 0) { |
||||
/* Note that this could just shut down directly; doing a trip through the
|
||||
shutdown path serves only a demonstration of the API. */ |
||||
grpc_em_fd_shutdown(&ap->read_em_fd); |
||||
grpc_em_fd_notify_on_read(&ap->read_em_fd, read_cb, ap, gpr_inf_future); |
||||
} else if (bytes_read == -1) { |
||||
if (errno == EAGAIN) { |
||||
grpc_em_fd_notify_on_read(&ap->read_em_fd, read_cb, ap, gpr_inf_future); |
||||
} else { |
||||
GPR_ASSERT(0 && strcat("unknown errno: ", strerror(errno))); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void dummy_cb(void *arg, /*async_pipe*/ enum grpc_em_cb_status status) {} |
||||
|
||||
void async_pipe_init(async_pipe *ap) { |
||||
int i; |
||||
|
||||
ap->num_write = 0; |
||||
ap->bytes_written_total = 0; |
||||
ap->bytes_read_total = 0; |
||||
|
||||
pthread_mutex_init(&ap->mu, NULL); |
||||
pthread_cond_init(&ap->cv, NULL); |
||||
ap->done = 0; |
||||
|
||||
GPR_ASSERT(0 == pipe(ap->fd)); |
||||
for (i = 0; i < 2; i++) { |
||||
int flags = fcntl(ap->fd[i], F_GETFL, 0); |
||||
GPR_ASSERT(fcntl(ap->fd[i], F_SETFL, flags | O_NONBLOCK) == 0); |
||||
GPR_ASSERT(fcntl(ap->fd[i], F_SETPIPE_SZ, 4096) == 4096); |
||||
} |
||||
|
||||
grpc_em_init(&ap->em); |
||||
grpc_em_fd_init(&ap->read_em_fd, &ap->em, ap->fd[0]); |
||||
grpc_em_fd_init(&ap->write_em_fd, &ap->em, ap->fd[1]); |
||||
} |
||||
|
||||
static void async_pipe_start(async_pipe *ap) { |
||||
grpc_em_fd_notify_on_read(&ap->read_em_fd, read_cb, ap, gpr_inf_future); |
||||
grpc_em_fd_notify_on_write(&ap->write_em_fd, write_cb, ap, gpr_inf_future); |
||||
} |
||||
|
||||
static void async_pipe_wait_destroy(async_pipe *ap) { |
||||
pthread_mutex_lock(&ap->mu); |
||||
while (!ap->done) pthread_cond_wait(&ap->cv, &ap->mu); |
||||
pthread_mutex_unlock(&ap->mu); |
||||
pthread_mutex_destroy(&ap->mu); |
||||
pthread_cond_destroy(&ap->cv); |
||||
|
||||
grpc_em_destroy(&ap->em); |
||||
} |
||||
|
||||
int main(int argc, char **argv) { |
||||
async_pipe ap; |
||||
grpc_test_init(argc, argv); |
||||
async_pipe_init(&ap); |
||||
async_pipe_start(&ap); |
||||
async_pipe_wait_destroy(&ap); |
||||
GPR_ASSERT(ap.bytes_read_total == ap.bytes_written_total); |
||||
gpr_log(GPR_INFO, "read total bytes %d", ap.bytes_read_total); |
||||
return 0; |
||||
} |
@ -0,0 +1,219 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
/* Test gRPC event manager with a simple TCP upload server and client. */ |
||||
#include "src/core/iomgr/alarm.h" |
||||
|
||||
#include <ctype.h> |
||||
#include <errno.h> |
||||
#include <fcntl.h> |
||||
#include <netinet/in.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <sys/socket.h> |
||||
#include <sys/time.h> |
||||
#include <unistd.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/sync.h> |
||||
#include <grpc/support/time.h> |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
/* Dummy gRPC callback */ |
||||
void no_op_cb(void *arg, grpc_iomgr_cb_status status) {} |
||||
|
||||
typedef struct { |
||||
gpr_cv cv; |
||||
gpr_mu mu; |
||||
int counter; |
||||
int done_success_ctr; |
||||
int done_cancel_ctr; |
||||
int done; |
||||
gpr_event fcb_arg; |
||||
grpc_iomgr_cb_status status; |
||||
} alarm_arg; |
||||
|
||||
static void followup_cb(void *arg, grpc_iomgr_cb_status status) { |
||||
gpr_event_set((gpr_event *)arg, arg); |
||||
} |
||||
|
||||
/* Called when an alarm expires. */ |
||||
static void alarm_cb(void *arg /* alarm_arg */, grpc_iomgr_cb_status status) { |
||||
alarm_arg *a = arg; |
||||
gpr_mu_lock(&a->mu); |
||||
if (status == GRPC_CALLBACK_SUCCESS) { |
||||
a->counter++; |
||||
a->done_success_ctr++; |
||||
} else if (status == GRPC_CALLBACK_CANCELLED) { |
||||
a->done_cancel_ctr++; |
||||
} else { |
||||
GPR_ASSERT(0); |
||||
} |
||||
a->done = 1; |
||||
a->status = status; |
||||
gpr_cv_signal(&a->cv); |
||||
gpr_mu_unlock(&a->mu); |
||||
grpc_iomgr_add_callback(followup_cb, &a->fcb_arg); |
||||
} |
||||
|
||||
/* Test grpc_alarm add and cancel. */ |
||||
static void test_grpc_alarm() { |
||||
grpc_alarm alarm; |
||||
grpc_alarm alarm_to_cancel; |
||||
gpr_timespec tv0 = {0, 1}; |
||||
/* Timeout on the alarm cond. var, so make big enough to absorb time
|
||||
deviations. Otherwise, operations after wait will not be properly ordered |
||||
*/ |
||||
gpr_timespec tv1 = gpr_time_from_micros(200000); |
||||
gpr_timespec tv2 = {0, 1}; |
||||
gpr_timespec alarm_deadline; |
||||
gpr_timespec followup_deadline; |
||||
|
||||
alarm_arg arg; |
||||
alarm_arg arg2; |
||||
void *fdone; |
||||
|
||||
grpc_iomgr_init(); |
||||
|
||||
arg.counter = 0; |
||||
arg.status = GRPC_CALLBACK_DO_NOT_USE; |
||||
arg.done_success_ctr = 0; |
||||
arg.done_cancel_ctr = 0; |
||||
arg.done = 0; |
||||
gpr_mu_init(&arg.mu); |
||||
gpr_cv_init(&arg.cv); |
||||
gpr_event_init(&arg.fcb_arg); |
||||
|
||||
grpc_alarm_init(&alarm, alarm_cb, &arg); |
||||
grpc_alarm_add(&alarm, gpr_time_add(tv0, gpr_now())); |
||||
|
||||
alarm_deadline = gpr_time_add(gpr_now(), tv1); |
||||
gpr_mu_lock(&arg.mu); |
||||
while (arg.done == 0) { |
||||
gpr_cv_wait(&arg.cv, &arg.mu, alarm_deadline); |
||||
} |
||||
gpr_mu_unlock(&arg.mu); |
||||
|
||||
followup_deadline = gpr_time_add(gpr_now(), tv1); |
||||
fdone = gpr_event_wait(&arg.fcb_arg, followup_deadline); |
||||
|
||||
if (arg.counter != 1) { |
||||
gpr_log(GPR_ERROR, "Alarm callback not called"); |
||||
GPR_ASSERT(0); |
||||
} else if (arg.done_success_ctr != 1) { |
||||
gpr_log(GPR_ERROR, "Alarm done callback not called with success"); |
||||
GPR_ASSERT(0); |
||||
} else if (arg.done_cancel_ctr != 0) { |
||||
gpr_log(GPR_ERROR, "Alarm done callback called with cancel"); |
||||
GPR_ASSERT(0); |
||||
} else if (arg.status == GRPC_CALLBACK_DO_NOT_USE) { |
||||
gpr_log(GPR_ERROR, "Alarm callback without status"); |
||||
GPR_ASSERT(0); |
||||
} else { |
||||
gpr_log(GPR_INFO, "Alarm callback called successfully"); |
||||
} |
||||
|
||||
if (fdone != (void *)&arg.fcb_arg) { |
||||
gpr_log(GPR_ERROR, "Followup callback #1 not invoked properly %p %p", fdone, |
||||
&arg.fcb_arg); |
||||
GPR_ASSERT(0); |
||||
} |
||||
gpr_cv_destroy(&arg.cv); |
||||
gpr_mu_destroy(&arg.mu); |
||||
|
||||
arg2.counter = 0; |
||||
arg2.status = GRPC_CALLBACK_DO_NOT_USE; |
||||
arg2.done_success_ctr = 0; |
||||
arg2.done_cancel_ctr = 0; |
||||
arg2.done = 0; |
||||
gpr_mu_init(&arg2.mu); |
||||
gpr_cv_init(&arg2.cv); |
||||
gpr_event_init(&arg2.fcb_arg); |
||||
|
||||
grpc_alarm_init(&alarm_to_cancel, alarm_cb, &arg2); |
||||
grpc_alarm_add(&alarm_to_cancel, gpr_time_add(tv2, gpr_now())); |
||||
grpc_alarm_cancel(&alarm_to_cancel); |
||||
|
||||
alarm_deadline = gpr_time_add(gpr_now(), tv1); |
||||
gpr_mu_lock(&arg2.mu); |
||||
while (arg2.done == 0) { |
||||
gpr_cv_wait(&arg2.cv, &arg2.mu, alarm_deadline); |
||||
} |
||||
gpr_mu_unlock(&arg2.mu); |
||||
|
||||
followup_deadline = gpr_time_add(gpr_now(), tv1); |
||||
fdone = gpr_event_wait(&arg2.fcb_arg, followup_deadline); |
||||
|
||||
if (arg2.counter != arg2.done_success_ctr) { |
||||
gpr_log(GPR_ERROR, "Alarm callback called but didn't lead to done success"); |
||||
GPR_ASSERT(0); |
||||
} else if (arg2.done_success_ctr && arg2.done_cancel_ctr) { |
||||
gpr_log(GPR_ERROR, "Alarm done callback called with success and cancel"); |
||||
GPR_ASSERT(0); |
||||
} else if (arg2.done_cancel_ctr + arg2.done_success_ctr != 1) { |
||||
gpr_log(GPR_ERROR, "Alarm done callback called incorrect number of times"); |
||||
GPR_ASSERT(0); |
||||
} else if (arg2.status == GRPC_CALLBACK_DO_NOT_USE) { |
||||
gpr_log(GPR_ERROR, "Alarm callback without status"); |
||||
GPR_ASSERT(0); |
||||
} else if (arg2.done_success_ctr) { |
||||
gpr_log(GPR_INFO, "Alarm callback executed before cancel"); |
||||
gpr_log(GPR_INFO, "Current value of triggered is %d\n", |
||||
(int)alarm_to_cancel.triggered); |
||||
} else if (arg2.done_cancel_ctr) { |
||||
gpr_log(GPR_INFO, "Alarm callback canceled"); |
||||
gpr_log(GPR_INFO, "Current value of triggered is %d\n", |
||||
(int)alarm_to_cancel.triggered); |
||||
} else { |
||||
gpr_log(GPR_ERROR, "Alarm cancel test should not be here"); |
||||
GPR_ASSERT(0); |
||||
} |
||||
|
||||
if (fdone != (void *)&arg2.fcb_arg) { |
||||
gpr_log(GPR_ERROR, "Followup callback #2 not invoked properly %p %p", fdone, |
||||
&arg2.fcb_arg); |
||||
GPR_ASSERT(0); |
||||
} |
||||
gpr_cv_destroy(&arg2.cv); |
||||
gpr_mu_destroy(&arg2.mu); |
||||
|
||||
grpc_iomgr_shutdown(); |
||||
} |
||||
|
||||
int main(int argc, char **argv) { |
||||
grpc_test_init(argc, argv); |
||||
test_grpc_alarm(); |
||||
return 0; |
||||
} |
@ -0,0 +1,176 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/iomgr/tcp_client.h" |
||||
|
||||
#include <errno.h> |
||||
#include <netinet/in.h> |
||||
#include <string.h> |
||||
#include <sys/socket.h> |
||||
#include <unistd.h> |
||||
|
||||
#include "src/core/iomgr/iomgr.h" |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/time.h> |
||||
|
||||
static gpr_timespec test_deadline() { |
||||
return gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)); |
||||
} |
||||
|
||||
static void must_succeed(void *arg, grpc_endpoint *tcp) { |
||||
GPR_ASSERT(tcp); |
||||
grpc_endpoint_shutdown(tcp); |
||||
grpc_endpoint_destroy(tcp); |
||||
gpr_event_set(arg, (void *)1); |
||||
} |
||||
|
||||
static void must_fail(void *arg, grpc_endpoint *tcp) { |
||||
GPR_ASSERT(!tcp); |
||||
gpr_event_set(arg, (void *)1); |
||||
} |
||||
|
||||
void test_succeeds() { |
||||
struct sockaddr_in addr; |
||||
socklen_t addr_len = sizeof(addr); |
||||
int svr_fd; |
||||
int r; |
||||
gpr_event ev; |
||||
|
||||
gpr_event_init(&ev); |
||||
|
||||
memset(&addr, 0, sizeof(addr)); |
||||
addr.sin_family = AF_INET; |
||||
|
||||
/* create a dummy server */ |
||||
svr_fd = socket(AF_INET, SOCK_STREAM, 0); |
||||
GPR_ASSERT(svr_fd >= 0); |
||||
GPR_ASSERT(0 == bind(svr_fd, (struct sockaddr *)&addr, addr_len)); |
||||
GPR_ASSERT(0 == listen(svr_fd, 1)); |
||||
|
||||
/* connect to it */ |
||||
GPR_ASSERT(getsockname(svr_fd, (struct sockaddr *)&addr, &addr_len) == 0); |
||||
grpc_tcp_client_connect(must_succeed, &ev, (struct sockaddr *)&addr, addr_len, |
||||
gpr_inf_future); |
||||
|
||||
/* await the connection */ |
||||
do { |
||||
addr_len = sizeof(addr); |
||||
r = accept(svr_fd, (struct sockaddr *)&addr, &addr_len); |
||||
} while (r == -1 && errno == EINTR); |
||||
GPR_ASSERT(r >= 0); |
||||
close(r); |
||||
|
||||
/* wait for the connection callback to finish */ |
||||
GPR_ASSERT(gpr_event_wait(&ev, test_deadline())); |
||||
} |
||||
|
||||
void test_fails() { |
||||
struct sockaddr_in addr; |
||||
socklen_t addr_len = sizeof(addr); |
||||
gpr_event ev; |
||||
|
||||
gpr_event_init(&ev); |
||||
|
||||
memset(&addr, 0, sizeof(addr)); |
||||
addr.sin_family = AF_INET; |
||||
|
||||
/* connect to a broken address */ |
||||
grpc_tcp_client_connect(must_fail, &ev, (struct sockaddr *)&addr, addr_len, |
||||
gpr_inf_future); |
||||
|
||||
/* wait for the connection callback to finish */ |
||||
GPR_ASSERT(gpr_event_wait(&ev, test_deadline())); |
||||
} |
||||
|
||||
void test_times_out() { |
||||
struct sockaddr_in addr; |
||||
socklen_t addr_len = sizeof(addr); |
||||
int svr_fd; |
||||
#define NUM_CLIENT_CONNECTS 10 |
||||
int client_fd[NUM_CLIENT_CONNECTS]; |
||||
int i; |
||||
int r; |
||||
gpr_event ev; |
||||
gpr_timespec connect_deadline; |
||||
|
||||
gpr_event_init(&ev); |
||||
|
||||
memset(&addr, 0, sizeof(addr)); |
||||
addr.sin_family = AF_INET; |
||||
|
||||
/* create a dummy server */ |
||||
svr_fd = socket(AF_INET, SOCK_STREAM, 0); |
||||
GPR_ASSERT(svr_fd >= 0); |
||||
GPR_ASSERT(0 == bind(svr_fd, (struct sockaddr *)&addr, addr_len)); |
||||
GPR_ASSERT(0 == listen(svr_fd, 1)); |
||||
/* Get its address */ |
||||
GPR_ASSERT(getsockname(svr_fd, (struct sockaddr *)&addr, &addr_len) == 0); |
||||
|
||||
/* tie up the listen buffer, which is somewhat arbitrarily sized. */ |
||||
for (i = 0; i < NUM_CLIENT_CONNECTS; ++i) { |
||||
client_fd[i] = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); |
||||
do { |
||||
r = connect(client_fd[i], (struct sockaddr *)&addr, addr_len); |
||||
} while (r == -1 && errno == EINTR); |
||||
GPR_ASSERT(r < 0); |
||||
GPR_ASSERT(errno == EWOULDBLOCK || errno == EINPROGRESS); |
||||
} |
||||
|
||||
/* connect to dummy server address */ |
||||
|
||||
connect_deadline = gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)); |
||||
|
||||
grpc_tcp_client_connect(must_fail, &ev, (struct sockaddr *)&addr, addr_len, |
||||
connect_deadline); |
||||
/* Make sure the event doesn't trigger early */ |
||||
GPR_ASSERT(!gpr_event_wait( |
||||
&ev, gpr_time_add(gpr_now(), gpr_time_from_micros(500000)))); |
||||
/* Now wait until it should have triggered */ |
||||
sleep(1); |
||||
|
||||
/* wait for the connection callback to finish */ |
||||
GPR_ASSERT(gpr_event_wait(&ev, test_deadline())); |
||||
close(svr_fd); |
||||
for (i = 0; i < NUM_CLIENT_CONNECTS; ++i) { |
||||
close(client_fd[i]); |
||||
} |
||||
} |
||||
|
||||
int main(void) { |
||||
grpc_iomgr_init(); |
||||
test_succeeds(); |
||||
test_fails(); |
||||
test_times_out(); |
||||
grpc_iomgr_shutdown(); |
||||
return 0; |
||||
} |
Loading…
Reference in new issue