mirror of https://github.com/grpc/grpc.git
commit
1d6072c56f
233 changed files with 24200 additions and 7773 deletions
@ -0,0 +1,9 @@ |
||||
*.iml |
||||
.gradle |
||||
/local.properties |
||||
/.idea/workspace.xml |
||||
/.idea/libraries |
||||
.DS_Store |
||||
/build |
||||
/captures |
||||
.externalNativeBuild |
@ -0,0 +1,24 @@ |
||||
gRPC on Android |
||||
============== |
||||
|
||||
Note: Building the protobuf dependency for Android requires |
||||
https://github.com/google/protobuf/pull/3878. This fix will be in the next |
||||
protobuf release, but until then must be manually patched in to |
||||
`third_party/protobuf` to build gRPC for Android. |
||||
|
||||
PREREQUISITES |
||||
------------- |
||||
|
||||
- Android SDK |
||||
- Android NDK |
||||
- `protoc` and `grpc_cpp_plugin` binaries on the host system |
||||
|
||||
INSTALL |
||||
------- |
||||
|
||||
The example application can be built via Android Studio or on the command line |
||||
using `gradle`: |
||||
|
||||
```sh |
||||
$ ./gradlew installDebug |
||||
``` |
@ -0,0 +1 @@ |
||||
/build |
@ -0,0 +1,123 @@ |
||||
cmake_minimum_required(VERSION 3.4.1) |
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") |
||||
|
||||
set(helloworld_PROTOBUF_PROTOC_EXECUTABLE "/usr/local/bin/protoc" CACHE STRING "Protoc binary on host") |
||||
set(helloworld_GRPC_CPP_PLUGIN_EXECUTABLE "/usr/local/bin/grpc_cpp_plugin" CACHE STRING "gRPC CPP plugin binary on host") |
||||
|
||||
set(GRPC_SRC_DIR ../../../../) |
||||
|
||||
set(GRPC_BUILD_DIR ../grpc/outputs/${ANDROID_ABI}) |
||||
file(MAKE_DIRECTORY ${GRPC_BUILD_DIR}) |
||||
|
||||
add_subdirectory(${GRPC_SRC_DIR} ${GRPC_BUILD_DIR}) |
||||
|
||||
include_directories(${GRPC_SRC_DIR}/include) |
||||
|
||||
add_library(libgrpc STATIC IMPORTED) |
||||
set_target_properties(libgrpc PROPERTIES IMPORTED_LOCATION |
||||
${GRPC_BUILD_DIR}/libgrpc.a) |
||||
|
||||
add_library(libgrpc++ STATIC IMPORTED) |
||||
set_target_properties(libgrpc++ PROPERTIES IMPORTED_LOCATION |
||||
${GRPC_BUILD_DIR}/libgrpc++.a) |
||||
|
||||
add_library(libgpr STATIC IMPORTED) |
||||
set_target_properties(libgpr PROPERTIES IMPORTED_LOCATION |
||||
${GRPC_BUILD_DIR}/libgpr.a) |
||||
|
||||
add_library(libcares STATIC IMPORTED) |
||||
set_target_properties(libcares PROPERTIES IMPORTED_LOCATION |
||||
${GRPC_BUILD_DIR}/third_party/cares/cares/lib/libcares.a) |
||||
|
||||
add_library(libzlib STATIC IMPORTED) |
||||
set_target_properties(libzlib PROPERTIES IMPORTED_LOCATION |
||||
${GRPC_BUILD_DIR}/third_party/zlib/libz.a) |
||||
|
||||
add_library(libcrypto STATIC IMPORTED) |
||||
set_target_properties(libcrypto PROPERTIES IMPORTED_LOCATION |
||||
${GRPC_BUILD_DIR}/third_party/boringssl/crypto/libcrypto.a) |
||||
|
||||
add_library(libssl STATIC IMPORTED) |
||||
set_target_properties(libssl PROPERTIES IMPORTED_LOCATION |
||||
${GRPC_BUILD_DIR}/third_party/boringssl/ssl/libssl.a) |
||||
|
||||
set(GRPC_PROTO_GENS_DIR ${CMAKE_BINARY_DIR}/gens) |
||||
file(MAKE_DIRECTORY ${GRPC_PROTO_GENS_DIR}) |
||||
include_directories(${GRPC_PROTO_GENS_DIR}) |
||||
|
||||
function(android_protobuf_grpc_generate_cpp SRC_FILES HDR_FILES INCLUDE_ROOT) |
||||
if(NOT ARGN) |
||||
message(SEND_ERROR "Error: android_protobuf_grpc_generate_cpp() called without any proto files") |
||||
return() |
||||
endif() |
||||
|
||||
set(${SRC_FILES}) |
||||
set(${HDR_FILES}) |
||||
set(PROTOBUF_INCLUDE_PATH -I ${INCLUDE_ROOT}) |
||||
foreach(FIL ${ARGN}) |
||||
get_filename_component(ABS_FIL ${FIL} ABSOLUTE) |
||||
get_filename_component(FIL_WE ${FIL} NAME_WE) |
||||
file(RELATIVE_PATH REL_FIL ${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_ROOT} ${ABS_FIL}) |
||||
get_filename_component(REL_DIR ${REL_FIL} DIRECTORY) |
||||
set(RELFIL_WE "${REL_DIR}/${FIL_WE}") |
||||
|
||||
list(APPEND ${SRC_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.cc") |
||||
list(APPEND ${HDR_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.h") |
||||
list(APPEND ${SRC_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.cc") |
||||
list(APPEND ${HDR_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.h") |
||||
|
||||
add_custom_command( |
||||
OUTPUT "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.cc" |
||||
"${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.h" |
||||
"${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.cc" |
||||
"${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.h" |
||||
COMMAND ${helloworld_PROTOBUF_PROTOC_EXECUTABLE} |
||||
ARGS --grpc_out=${GRPC_PROTO_GENS_DIR} |
||||
--cpp_out=${GRPC_PROTO_GENS_DIR} |
||||
--plugin=protoc-gen-grpc=${helloworld_GRPC_CPP_PLUGIN_EXECUTABLE} |
||||
${PROTOBUF_INCLUDE_PATH} |
||||
${REL_FIL} |
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} |
||||
DEPENDS ${helloworld_PROTOBUF_PROTOC_EXECUTABLE} ${helloworld_GRPC_CPP_PLUGIN_EXECUTABLE} ${ABS_FIL} ) |
||||
endforeach() |
||||
|
||||
set_source_files_properties(${${SRC_FILES}} ${${HDR_FILES}} PROPERTIES GENERATED TRUE) |
||||
set(${SRC_FILES} ${${SRC_FILES}} PARENT_SCOPE) |
||||
set(${HDR_FILES} ${${HDR_FILES}} PARENT_SCOPE) |
||||
endfunction() |
||||
|
||||
set(PROTO_BASE_DIR ${GRPC_SRC_DIR}/examples/protos) |
||||
|
||||
android_protobuf_grpc_generate_cpp( |
||||
HELLOWORLD_PROTO_SRCS HELLOWORLD_PROTO_HDRS ${PROTO_BASE_DIR} ${PROTO_BASE_DIR}/helloworld.proto) |
||||
|
||||
add_library(helloworld_proto_lib |
||||
SHARED ${HELLOWORLD_PROTO_HDRS} ${HELLOWORLD_PROTO_SRCS}) |
||||
|
||||
target_link_libraries(helloworld_proto_lib |
||||
libprotobuf |
||||
libgrpc++ |
||||
android |
||||
log) |
||||
|
||||
find_library(log-lib |
||||
log) |
||||
|
||||
add_library(grpc-helloworld |
||||
SHARED src/main/cpp/grpc-helloworld.cc) |
||||
|
||||
target_include_directories(grpc-helloworld |
||||
PRIVATE ${HELLOWORLD_PROTO_HEADERS}) |
||||
|
||||
target_link_libraries(grpc-helloworld |
||||
libgrpc++ |
||||
libgrpc |
||||
libzlib |
||||
libcares |
||||
libssl |
||||
libcrypto |
||||
helloworld_proto_lib |
||||
libgpr |
||||
android |
||||
${log-lib}) |
@ -0,0 +1,53 @@ |
||||
apply plugin: 'com.android.application' |
||||
|
||||
android { |
||||
compileSdkVersion 26 |
||||
defaultConfig { |
||||
applicationId "io.grpc.android.cpp.helloworldexample" |
||||
minSdkVersion 14 |
||||
targetSdkVersion 26 |
||||
versionCode 1 |
||||
versionName "1.0" |
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" |
||||
externalNativeBuild { |
||||
cmake { |
||||
cppFlags "-std=c++14 -frtti -fexceptions" |
||||
arguments '-DANDROID_STL=c++_static' |
||||
arguments '-DRUN_HAVE_POSIX_REGEX=0' |
||||
arguments '-DRUN_HAVE_STD_REGEX=0' |
||||
arguments '-DRUN_HAVE_STEADY_CLOCK=0' |
||||
arguments '-Dprotobuf_BUILD_PROTOC_BINARIES=off' |
||||
arguments '-DgRPC_BUILD_CODEGEN=off' |
||||
// Set this to the path to the protoc binary on the host system (codegen is not |
||||
// cross-compiled to Android) |
||||
arguments '-Dhelloworld_PROTOBUF_PROTOC_EXECUTABLE=/usr/local/bin/protoc' |
||||
// Set this to the path to the gRPC C++ protoc plugin binary on the host system |
||||
// (codegen is not cross-compiled to Android) |
||||
arguments '-Dhelloworld_GRPC_CPP_PLUGIN_EXECUTABLE=/usr/local/bin/grpc_cpp_plugin' |
||||
} |
||||
} |
||||
ndk.abiFilters 'x86' |
||||
} |
||||
buildTypes { |
||||
debug { |
||||
minifyEnabled false |
||||
} |
||||
release { |
||||
minifyEnabled true |
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' |
||||
} |
||||
} |
||||
externalNativeBuild { |
||||
cmake { |
||||
path "CMakeLists.txt" |
||||
} |
||||
} |
||||
} |
||||
|
||||
dependencies { |
||||
implementation fileTree(dir: 'libs', include: ['*.jar']) |
||||
implementation 'com.android.support:appcompat-v7:26.1.0' |
||||
testImplementation 'junit:junit:4.12' |
||||
androidTestImplementation 'com.android.support.test:runner:1.0.1' |
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' |
||||
} |
@ -0,0 +1,21 @@ |
||||
# Add project specific ProGuard rules here. |
||||
# You can control the set of applied configuration files using the |
||||
# proguardFiles setting in build.gradle. |
||||
# |
||||
# For more details, see |
||||
# http://developer.android.com/guide/developing/tools/proguard.html |
||||
|
||||
# If your project uses WebView with JS, uncomment the following |
||||
# and specify the fully qualified class name to the JavaScript interface |
||||
# class: |
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { |
||||
# public *; |
||||
#} |
||||
|
||||
# Uncomment this to preserve the line number information for |
||||
# debugging stack traces. |
||||
#-keepattributes SourceFile,LineNumberTable |
||||
|
||||
# If you keep the line number information, uncomment this to |
||||
# hide the original source file name. |
||||
#-renamesourcefileattribute SourceFile |
@ -0,0 +1,22 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
||||
package="io.grpc.helloworldexample.cpp" > |
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" /> |
||||
|
||||
<application |
||||
android:allowBackup="false" |
||||
android:icon="@mipmap/ic_launcher" |
||||
android:label="@string/app_name" |
||||
android:theme="@style/Base.V7.Theme.AppCompat.Light" > |
||||
<activity |
||||
android:name=".HelloworldActivity" |
||||
android:label="@string/app_name" > |
||||
<intent-filter> |
||||
<action android:name="android.intent.action.MAIN" /> |
||||
<category android:name="android.intent.category.LAUNCHER" /> |
||||
</intent-filter> |
||||
</activity> |
||||
</application> |
||||
|
||||
</manifest> |
@ -0,0 +1,142 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <atomic> |
||||
|
||||
#include <grpc++/grpc++.h> |
||||
#include <jni.h> |
||||
|
||||
#include "helloworld.grpc.pb.h" |
||||
|
||||
using grpc::Channel; |
||||
using grpc::ClientContext; |
||||
using grpc::Server; |
||||
using grpc::ServerBuilder; |
||||
using grpc::ServerContext; |
||||
using grpc::Status; |
||||
using helloworld::Greeter; |
||||
using helloworld::HelloReply; |
||||
using helloworld::HelloRequest; |
||||
|
||||
std::atomic<bool> stop_server(false); |
||||
|
||||
// Logic and data behind the server's behavior.
|
||||
class GreeterServiceImpl final : public Greeter::Service { |
||||
Status SayHello(ServerContext* context, const HelloRequest* request, |
||||
HelloReply* reply) override { |
||||
std::string prefix("Hello "); |
||||
reply->set_message(prefix + request->name()); |
||||
return Status::OK; |
||||
} |
||||
}; |
||||
|
||||
void StartServer(JNIEnv* env, jobject obj, jmethodID is_cancelled_mid, |
||||
int port) { |
||||
const int host_port_buf_size = 1024; |
||||
char host_port[host_port_buf_size]; |
||||
snprintf(host_port, host_port_buf_size, "0.0.0.0:%d", port); |
||||
|
||||
GreeterServiceImpl service; |
||||
ServerBuilder builder; |
||||
// Listen on the given address without any authentication mechanism.
|
||||
builder.AddListeningPort(host_port, grpc::InsecureServerCredentials()); |
||||
// Register "service" as the instance through which we'll communicate with
|
||||
// clients. In this case it corresponds to an *synchronous* service.
|
||||
builder.RegisterService(&service); |
||||
// Finally assemble the server.
|
||||
std::unique_ptr<Server> server(builder.BuildAndStart()); |
||||
while (!stop_server.load()) { |
||||
// Check with the Java code to see if the user has requested the server stop or the app is no
|
||||
// longer in the foreground.
|
||||
jboolean is_cancelled = env->CallBooleanMethod(obj, is_cancelled_mid); |
||||
if (is_cancelled == JNI_TRUE) { |
||||
stop_server = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
class GreeterClient { |
||||
public: |
||||
GreeterClient(std::shared_ptr<Channel> channel) |
||||
: stub_(Greeter::NewStub(channel)) {} |
||||
|
||||
// Assembles the client's payload, sends it and presents the response back
|
||||
// from the server.
|
||||
std::string SayHello(const std::string& user) { |
||||
// Data we are sending to the server.
|
||||
HelloRequest request; |
||||
request.set_name(user); |
||||
|
||||
// Container for the data we expect from the server.
|
||||
HelloReply reply; |
||||
|
||||
// Context for the client. It could be used to convey extra information to
|
||||
// the server and/or tweak certain RPC behaviors.
|
||||
ClientContext context; |
||||
// The actual RPC.
|
||||
Status status = stub_->SayHello(&context, request, &reply); |
||||
|
||||
if (status.ok()) { |
||||
return reply.message(); |
||||
} else { |
||||
return status.error_message(); |
||||
} |
||||
} |
||||
|
||||
private: |
||||
std::unique_ptr<Greeter::Stub> stub_; |
||||
}; |
||||
|
||||
// Send an RPC and return the response. Invoked from Java code.
|
||||
extern "C" JNIEXPORT jstring JNICALL |
||||
Java_io_grpc_helloworldexample_cpp_HelloworldActivity_sayHello( |
||||
JNIEnv* env, jobject obj_unused, jstring host_raw, jint port_raw, |
||||
jstring message_raw) { |
||||
const char* host_chars = env->GetStringUTFChars(host_raw, (jboolean*)0); |
||||
std::string host(host_chars, env->GetStringUTFLength(host_raw)); |
||||
|
||||
int port = static_cast<int>(port_raw); |
||||
|
||||
const char* message_chars = env->GetStringUTFChars(message_raw, (jboolean*)0); |
||||
std::string message(message_chars, env->GetStringUTFLength(message_raw)); |
||||
|
||||
const int host_port_buf_size = 1024; |
||||
char host_port[host_port_buf_size]; |
||||
snprintf(host_port, host_port_buf_size, "%s:%d", host.c_str(), port); |
||||
|
||||
GreeterClient greeter( |
||||
grpc::CreateChannel(host_port, grpc::InsecureChannelCredentials())); |
||||
std::string reply = greeter.SayHello(message); |
||||
|
||||
return env->NewStringUTF(reply.c_str()); |
||||
} |
||||
|
||||
// Start the server. Invoked from Java code.
|
||||
extern "C" JNIEXPORT void JNICALL |
||||
Java_io_grpc_helloworldexample_cpp_HelloworldActivity_startServer( |
||||
JNIEnv* env, jobject obj_this, jint port_raw) { |
||||
int port = static_cast<int>(port_raw); |
||||
|
||||
jclass cls = env->GetObjectClass(obj_this); |
||||
jmethodID is_cancelled_mid = |
||||
env->GetMethodID(cls, "isRunServerTaskCancelled", "()Z"); |
||||
|
||||
stop_server = false; |
||||
|
||||
StartServer(env, obj_this, is_cancelled_mid, port); |
||||
} |
@ -0,0 +1,167 @@ |
||||
/* |
||||
* Copyright 2018, gRPC Authors All rights reserved. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.grpc.helloworldexample.cpp; |
||||
|
||||
import android.content.Context; |
||||
import android.os.AsyncTask; |
||||
import android.os.Bundle; |
||||
import android.support.v7.app.AppCompatActivity; |
||||
import android.text.TextUtils; |
||||
import android.text.method.ScrollingMovementMethod; |
||||
import android.view.View; |
||||
import android.view.inputmethod.InputMethodManager; |
||||
import android.widget.Button; |
||||
import android.widget.EditText; |
||||
import android.widget.TextView; |
||||
import android.widget.Toast; |
||||
import java.lang.ref.WeakReference; |
||||
|
||||
public class HelloworldActivity extends AppCompatActivity { |
||||
|
||||
static { |
||||
System.loadLibrary("grpc-helloworld"); |
||||
} |
||||
|
||||
private Button sendButton; |
||||
private Button serverButton; |
||||
private EditText hostEdit; |
||||
private EditText portEdit; |
||||
private EditText messageEdit; |
||||
private EditText serverPortEdit; |
||||
private TextView resultText; |
||||
private GrpcTask grpcTask; |
||||
private RunServerTask runServerTask; |
||||
|
||||
@Override |
||||
protected void onCreate(Bundle savedInstanceState) { |
||||
super.onCreate(savedInstanceState); |
||||
setContentView(R.layout.activity_helloworld); |
||||
sendButton = (Button) findViewById(R.id.send_button); |
||||
serverButton = (Button) findViewById(R.id.server_button); |
||||
hostEdit = (EditText) findViewById(R.id.host_edit_text); |
||||
portEdit = (EditText) findViewById(R.id.port_edit_text); |
||||
messageEdit = (EditText) findViewById(R.id.message_edit_text); |
||||
serverPortEdit = (EditText) findViewById(R.id.server_port_edit_text); |
||||
resultText = (TextView) findViewById(R.id.grpc_response_text); |
||||
resultText.setMovementMethod(new ScrollingMovementMethod()); |
||||
} |
||||
|
||||
@Override |
||||
protected void onPause() { |
||||
super.onPause(); |
||||
if (runServerTask != null) { |
||||
runServerTask.cancel(true); |
||||
runServerTask = null; |
||||
serverButton.setText("Start gRPC Server"); |
||||
} |
||||
if (grpcTask != null) { |
||||
grpcTask.cancel(true); |
||||
grpcTask = null; |
||||
} |
||||
} |
||||
|
||||
public void sendMessage(View view) { |
||||
((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)) |
||||
.hideSoftInputFromWindow(hostEdit.getWindowToken(), 0); |
||||
sendButton.setEnabled(false); |
||||
resultText.setText(""); |
||||
grpcTask = new GrpcTask(this); |
||||
grpcTask.executeOnExecutor( |
||||
AsyncTask.THREAD_POOL_EXECUTOR, |
||||
hostEdit.getText().toString(), |
||||
messageEdit.getText().toString(), |
||||
portEdit.getText().toString()); |
||||
} |
||||
|
||||
public void startOrStopServer(View view) { |
||||
if (runServerTask != null) { |
||||
runServerTask.cancel(true); |
||||
runServerTask = null; |
||||
serverButton.setText("Start gRPC Server"); |
||||
Toast.makeText(this, "Server stopped", Toast.LENGTH_SHORT).show(); |
||||
} else { |
||||
runServerTask = new RunServerTask(this); |
||||
String portStr = serverPortEdit.getText().toString(); |
||||
int port = TextUtils.isEmpty(portStr) ? 50051 : Integer.valueOf(portStr); |
||||
runServerTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, port); |
||||
serverButton.setText("Stop gRPC Server"); |
||||
Toast.makeText(this, "Server started on port " + port, Toast.LENGTH_SHORT).show(); |
||||
} |
||||
} |
||||
|
||||
private static class RunServerTask extends AsyncTask<Integer, Void, Void> { |
||||
private final WeakReference<HelloworldActivity> activityReference; |
||||
|
||||
private RunServerTask(HelloworldActivity activity) { |
||||
this.activityReference = new WeakReference<HelloworldActivity>(activity); |
||||
} |
||||
|
||||
@Override |
||||
protected Void doInBackground(Integer... params) { |
||||
int port = params[0]; |
||||
HelloworldActivity activity = activityReference.get(); |
||||
if (activity != null) { |
||||
activity.startServer(port); |
||||
} |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
private static class GrpcTask extends AsyncTask<String, Void, String> { |
||||
private final WeakReference<HelloworldActivity> activityReference; |
||||
|
||||
private GrpcTask(HelloworldActivity activity) { |
||||
this.activityReference = new WeakReference<HelloworldActivity>(activity); |
||||
} |
||||
|
||||
@Override |
||||
protected String doInBackground(String... params) { |
||||
String host = params[0]; |
||||
String message = params[1]; |
||||
String portStr = params[2]; |
||||
int port = TextUtils.isEmpty(portStr) ? 50051 : Integer.valueOf(portStr); |
||||
return sayHello(host, port, message); |
||||
} |
||||
|
||||
@Override |
||||
protected void onPostExecute(String result) { |
||||
HelloworldActivity activity = activityReference.get(); |
||||
if (activity == null || isCancelled()) { |
||||
return; |
||||
} |
||||
TextView resultText = (TextView) activity.findViewById(R.id.grpc_response_text); |
||||
Button sendButton = (Button) activity.findViewById(R.id.send_button); |
||||
resultText.setText(result); |
||||
sendButton.setEnabled(true); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Invoked by native code to stop server when RunServerTask has been canceled, either by user |
||||
* request or upon app moving to background. |
||||
*/ |
||||
public boolean isRunServerTaskCancelled() { |
||||
if (runServerTask != null) { |
||||
return runServerTask.isCancelled(); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public static native String sayHello(String host, int port, String message); |
||||
|
||||
public native void startServer(int port); |
||||
} |
@ -0,0 +1,86 @@ |
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
tools:context=".HelloworldActivity" |
||||
android:orientation="vertical" > |
||||
|
||||
<TextView |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:paddingTop="12dp" |
||||
android:paddingBottom="12dp" |
||||
android:textSize="16sp" |
||||
android:text="gRPC Client Configuration" |
||||
android:textStyle="bold" /> |
||||
|
||||
<LinearLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:orientation="horizontal"> |
||||
<EditText |
||||
android:id="@+id/host_edit_text" |
||||
android:layout_weight="2" |
||||
android:layout_width="0dp" |
||||
android:layout_height="wrap_content" |
||||
android:hint="Enter Host" /> |
||||
<EditText |
||||
android:id="@+id/port_edit_text" |
||||
android:layout_weight="1" |
||||
android:layout_width="0dp" |
||||
android:layout_height="wrap_content" |
||||
android:inputType="numberDecimal" |
||||
android:hint="Enter Port" /> |
||||
</LinearLayout> |
||||
|
||||
|
||||
<EditText |
||||
android:id="@+id/message_edit_text" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:hint="Enter message to send" /> |
||||
|
||||
<Button |
||||
android:id="@+id/send_button" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:onClick="sendMessage" |
||||
android:text="Send gRPC Request" /> |
||||
|
||||
<TextView |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:paddingTop="12dp" |
||||
android:paddingBottom="12dp" |
||||
android:textSize="16sp" |
||||
android:text="Response:" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/grpc_response_text" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:scrollbars = "vertical" |
||||
android:textSize="16sp" /> |
||||
|
||||
<TextView |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:paddingTop="12dp" |
||||
android:paddingBottom="12dp" |
||||
android:textSize="16sp" |
||||
android:text="gRPC Server Configuration" |
||||
android:textStyle="bold" /> |
||||
|
||||
<EditText |
||||
android:id="@+id/server_port_edit_text" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:hint="Server port" /> |
||||
|
||||
<Button |
||||
android:id="@+id/server_button" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:onClick="startOrStopServer" |
||||
android:text="Start gRPC Server" /> |
||||
|
||||
</LinearLayout> |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 7.5 KiB |
@ -0,0 +1,3 @@ |
||||
<resources> |
||||
<string name="app_name">GrpcHelloworldCppExample</string> |
||||
</resources> |
@ -0,0 +1,24 @@ |
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules. |
||||
|
||||
buildscript { |
||||
repositories { |
||||
google() |
||||
jcenter() |
||||
} |
||||
dependencies { |
||||
classpath 'com.android.tools.build:gradle:3.0.1' |
||||
// NOTE: Do not place your application dependencies here; they belong |
||||
// in the individual module build.gradle files |
||||
} |
||||
} |
||||
|
||||
allprojects { |
||||
repositories { |
||||
google() |
||||
jcenter() |
||||
} |
||||
} |
||||
|
||||
task clean(type: Delete) { |
||||
delete rootProject.buildDir |
||||
} |
@ -0,0 +1,17 @@ |
||||
# Project-wide Gradle settings. |
||||
|
||||
# IDE (e.g. Android Studio) users: |
||||
# Gradle settings configured through the IDE *will override* |
||||
# any settings specified in this file. |
||||
|
||||
# For more details on how to configure your build environment visit |
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html |
||||
|
||||
# Specifies the JVM arguments used for the daemon process. |
||||
# The setting is particularly useful for tweaking memory settings. |
||||
org.gradle.jvmargs=-Xmx1536m |
||||
|
||||
# When configured, Gradle will run in incubating parallel mode. |
||||
# This option should only be used with decoupled projects. More details, visit |
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects |
||||
# org.gradle.parallel=true |
Binary file not shown.
@ -0,0 +1,6 @@ |
||||
#Thu Jan 25 11:45:30 PST 2018 |
||||
distributionBase=GRADLE_USER_HOME |
||||
distributionPath=wrapper/dists |
||||
zipStoreBase=GRADLE_USER_HOME |
||||
zipStorePath=wrapper/dists |
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip |
@ -0,0 +1,160 @@ |
||||
#!/usr/bin/env bash |
||||
|
||||
############################################################################## |
||||
## |
||||
## Gradle start up script for UN*X |
||||
## |
||||
############################################################################## |
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. |
||||
DEFAULT_JVM_OPTS="" |
||||
|
||||
APP_NAME="Gradle" |
||||
APP_BASE_NAME=`basename "$0"` |
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value. |
||||
MAX_FD="maximum" |
||||
|
||||
warn ( ) { |
||||
echo "$*" |
||||
} |
||||
|
||||
die ( ) { |
||||
echo |
||||
echo "$*" |
||||
echo |
||||
exit 1 |
||||
} |
||||
|
||||
# OS specific support (must be 'true' or 'false'). |
||||
cygwin=false |
||||
msys=false |
||||
darwin=false |
||||
case "`uname`" in |
||||
CYGWIN* ) |
||||
cygwin=true |
||||
;; |
||||
Darwin* ) |
||||
darwin=true |
||||
;; |
||||
MINGW* ) |
||||
msys=true |
||||
;; |
||||
esac |
||||
|
||||
# Attempt to set APP_HOME |
||||
# Resolve links: $0 may be a link |
||||
PRG="$0" |
||||
# Need this for relative symlinks. |
||||
while [ -h "$PRG" ] ; do |
||||
ls=`ls -ld "$PRG"` |
||||
link=`expr "$ls" : '.*-> \(.*\)$'` |
||||
if expr "$link" : '/.*' > /dev/null; then |
||||
PRG="$link" |
||||
else |
||||
PRG=`dirname "$PRG"`"/$link" |
||||
fi |
||||
done |
||||
SAVED="`pwd`" |
||||
cd "`dirname \"$PRG\"`/" >/dev/null |
||||
APP_HOME="`pwd -P`" |
||||
cd "$SAVED" >/dev/null |
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar |
||||
|
||||
# Determine the Java command to use to start the JVM. |
||||
if [ -n "$JAVA_HOME" ] ; then |
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then |
||||
# IBM's JDK on AIX uses strange locations for the executables |
||||
JAVACMD="$JAVA_HOME/jre/sh/java" |
||||
else |
||||
JAVACMD="$JAVA_HOME/bin/java" |
||||
fi |
||||
if [ ! -x "$JAVACMD" ] ; then |
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME |
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the |
||||
location of your Java installation." |
||||
fi |
||||
else |
||||
JAVACMD="java" |
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. |
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the |
||||
location of your Java installation." |
||||
fi |
||||
|
||||
# Increase the maximum file descriptors if we can. |
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then |
||||
MAX_FD_LIMIT=`ulimit -H -n` |
||||
if [ $? -eq 0 ] ; then |
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then |
||||
MAX_FD="$MAX_FD_LIMIT" |
||||
fi |
||||
ulimit -n $MAX_FD |
||||
if [ $? -ne 0 ] ; then |
||||
warn "Could not set maximum file descriptor limit: $MAX_FD" |
||||
fi |
||||
else |
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" |
||||
fi |
||||
fi |
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock |
||||
if $darwin; then |
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" |
||||
fi |
||||
|
||||
# For Cygwin, switch paths to Windows format before running java |
||||
if $cygwin ; then |
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"` |
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` |
||||
JAVACMD=`cygpath --unix "$JAVACMD"` |
||||
|
||||
# We build the pattern for arguments to be converted via cygpath |
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` |
||||
SEP="" |
||||
for dir in $ROOTDIRSRAW ; do |
||||
ROOTDIRS="$ROOTDIRS$SEP$dir" |
||||
SEP="|" |
||||
done |
||||
OURCYGPATTERN="(^($ROOTDIRS))" |
||||
# Add a user-defined pattern to the cygpath arguments |
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then |
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" |
||||
fi |
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh |
||||
i=0 |
||||
for arg in "$@" ; do |
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` |
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option |
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition |
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` |
||||
else |
||||
eval `echo args$i`="\"$arg\"" |
||||
fi |
||||
i=$((i+1)) |
||||
done |
||||
case $i in |
||||
(0) set -- ;; |
||||
(1) set -- "$args0" ;; |
||||
(2) set -- "$args0" "$args1" ;; |
||||
(3) set -- "$args0" "$args1" "$args2" ;; |
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;; |
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; |
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; |
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; |
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; |
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; |
||||
esac |
||||
fi |
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules |
||||
function splitJvmOpts() { |
||||
JVM_OPTS=("$@") |
||||
} |
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS |
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" |
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" |
@ -0,0 +1,90 @@ |
||||
@if "%DEBUG%" == "" @echo off |
||||
@rem ########################################################################## |
||||
@rem |
||||
@rem Gradle startup script for Windows |
||||
@rem |
||||
@rem ########################################################################## |
||||
|
||||
@rem Set local scope for the variables with windows NT shell |
||||
if "%OS%"=="Windows_NT" setlocal |
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. |
||||
set DEFAULT_JVM_OPTS= |
||||
|
||||
set DIRNAME=%~dp0 |
||||
if "%DIRNAME%" == "" set DIRNAME=. |
||||
set APP_BASE_NAME=%~n0 |
||||
set APP_HOME=%DIRNAME% |
||||
|
||||
@rem Find java.exe |
||||
if defined JAVA_HOME goto findJavaFromJavaHome |
||||
|
||||
set JAVA_EXE=java.exe |
||||
%JAVA_EXE% -version >NUL 2>&1 |
||||
if "%ERRORLEVEL%" == "0" goto init |
||||
|
||||
echo. |
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. |
||||
echo. |
||||
echo Please set the JAVA_HOME variable in your environment to match the |
||||
echo location of your Java installation. |
||||
|
||||
goto fail |
||||
|
||||
:findJavaFromJavaHome |
||||
set JAVA_HOME=%JAVA_HOME:"=% |
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe |
||||
|
||||
if exist "%JAVA_EXE%" goto init |
||||
|
||||
echo. |
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% |
||||
echo. |
||||
echo Please set the JAVA_HOME variable in your environment to match the |
||||
echo location of your Java installation. |
||||
|
||||
goto fail |
||||
|
||||
:init |
||||
@rem Get command-line arguments, handling Windowz variants |
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args |
||||
if "%@eval[2+2]" == "4" goto 4NT_args |
||||
|
||||
:win9xME_args |
||||
@rem Slurp the command line arguments. |
||||
set CMD_LINE_ARGS= |
||||
set _SKIP=2 |
||||
|
||||
:win9xME_args_slurp |
||||
if "x%~1" == "x" goto execute |
||||
|
||||
set CMD_LINE_ARGS=%* |
||||
goto execute |
||||
|
||||
:4NT_args |
||||
@rem Get arguments from the 4NT Shell from JP Software |
||||
set CMD_LINE_ARGS=%$ |
||||
|
||||
:execute |
||||
@rem Setup the command line |
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar |
||||
|
||||
@rem Execute Gradle |
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% |
||||
|
||||
:end |
||||
@rem End local scope for the variables with windows NT shell |
||||
if "%ERRORLEVEL%"=="0" goto mainEnd |
||||
|
||||
:fail |
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of |
||||
rem the _cmd.exe /c_ return code! |
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 |
||||
exit /b 1 |
||||
|
||||
:mainEnd |
||||
if "%OS%"=="Windows_NT" endlocal |
||||
|
||||
:omega |
@ -0,0 +1 @@ |
||||
include ':app' |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,100 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2017 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/ext/filters/client_channel/status_util.h" |
||||
|
||||
#include "src/core/lib/gpr/useful.h" |
||||
|
||||
typedef struct { |
||||
const char* str; |
||||
grpc_status_code status; |
||||
} status_string_entry; |
||||
|
||||
static const status_string_entry g_status_string_entries[] = { |
||||
{"OK", GRPC_STATUS_OK}, |
||||
{"CANCELLED", GRPC_STATUS_CANCELLED}, |
||||
{"UNKNOWN", GRPC_STATUS_UNKNOWN}, |
||||
{"INVALID_ARGUMENT", GRPC_STATUS_INVALID_ARGUMENT}, |
||||
{"DEADLINE_EXCEEDED", GRPC_STATUS_DEADLINE_EXCEEDED}, |
||||
{"NOT_FOUND", GRPC_STATUS_NOT_FOUND}, |
||||
{"ALREADY_EXISTS", GRPC_STATUS_ALREADY_EXISTS}, |
||||
{"PERMISSION_DENIED", GRPC_STATUS_PERMISSION_DENIED}, |
||||
{"UNAUTHENTICATED", GRPC_STATUS_UNAUTHENTICATED}, |
||||
{"RESOURCE_EXHAUSTED", GRPC_STATUS_RESOURCE_EXHAUSTED}, |
||||
{"FAILED_PRECONDITION", GRPC_STATUS_FAILED_PRECONDITION}, |
||||
{"ABORTED", GRPC_STATUS_ABORTED}, |
||||
{"OUT_OF_RANGE", GRPC_STATUS_OUT_OF_RANGE}, |
||||
{"UNIMPLEMENTED", GRPC_STATUS_UNIMPLEMENTED}, |
||||
{"INTERNAL", GRPC_STATUS_INTERNAL}, |
||||
{"UNAVAILABLE", GRPC_STATUS_UNAVAILABLE}, |
||||
{"DATA_LOSS", GRPC_STATUS_DATA_LOSS}, |
||||
}; |
||||
|
||||
bool grpc_status_code_from_string(const char* status_str, |
||||
grpc_status_code* status) { |
||||
for (size_t i = 0; i < GPR_ARRAY_SIZE(g_status_string_entries); ++i) { |
||||
if (strcmp(status_str, g_status_string_entries[i].str) == 0) { |
||||
*status = g_status_string_entries[i].status; |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
const char* grpc_status_code_to_string(grpc_status_code status) { |
||||
switch (status) { |
||||
case GRPC_STATUS_OK: |
||||
return "OK"; |
||||
case GRPC_STATUS_CANCELLED: |
||||
return "CANCELLED"; |
||||
case GRPC_STATUS_UNKNOWN: |
||||
return "UNKNOWN"; |
||||
case GRPC_STATUS_INVALID_ARGUMENT: |
||||
return "INVALID_ARGUMENT"; |
||||
case GRPC_STATUS_DEADLINE_EXCEEDED: |
||||
return "DEADLINE_EXCEEDED"; |
||||
case GRPC_STATUS_NOT_FOUND: |
||||
return "NOT_FOUND"; |
||||
case GRPC_STATUS_ALREADY_EXISTS: |
||||
return "ALREADY_EXISTS"; |
||||
case GRPC_STATUS_PERMISSION_DENIED: |
||||
return "PERMISSION_DENIED"; |
||||
case GRPC_STATUS_UNAUTHENTICATED: |
||||
return "UNAUTHENTICATED"; |
||||
case GRPC_STATUS_RESOURCE_EXHAUSTED: |
||||
return "RESOURCE_EXHAUSTED"; |
||||
case GRPC_STATUS_FAILED_PRECONDITION: |
||||
return "FAILED_PRECONDITION"; |
||||
case GRPC_STATUS_ABORTED: |
||||
return "ABORTED"; |
||||
case GRPC_STATUS_OUT_OF_RANGE: |
||||
return "OUT_OF_RANGE"; |
||||
case GRPC_STATUS_UNIMPLEMENTED: |
||||
return "UNIMPLEMENTED"; |
||||
case GRPC_STATUS_INTERNAL: |
||||
return "INTERNAL"; |
||||
case GRPC_STATUS_UNAVAILABLE: |
||||
return "UNAVAILABLE"; |
||||
case GRPC_STATUS_DATA_LOSS: |
||||
return "DATA_LOSS"; |
||||
default: |
||||
return "UNKNOWN"; |
||||
} |
||||
} |
@ -0,0 +1,58 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2017 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_STATUS_UTIL_H |
||||
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_STATUS_UTIL_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <grpc/status.h> |
||||
|
||||
#include <stdbool.h> |
||||
#include <string.h> |
||||
|
||||
/// If \a status_str is a valid status string, sets \a status to the
|
||||
/// corresponding status value and returns true.
|
||||
bool grpc_status_code_from_string(const char* status_str, |
||||
grpc_status_code* status); |
||||
|
||||
/// Returns the string form of \a status, or "UNKNOWN" if invalid.
|
||||
const char* grpc_status_code_to_string(grpc_status_code status); |
||||
|
||||
namespace grpc_core { |
||||
namespace internal { |
||||
|
||||
/// A set of grpc_status_code values.
|
||||
class StatusCodeSet { |
||||
public: |
||||
bool Empty() const { return status_code_mask_ == 0; } |
||||
|
||||
void Add(grpc_status_code status) { status_code_mask_ |= (1 << status); } |
||||
|
||||
bool Contains(grpc_status_code status) const { |
||||
return status_code_mask_ & (1 << status); |
||||
} |
||||
|
||||
private: |
||||
int status_code_mask_ = 0; // A bitfield of status codes in the set.
|
||||
}; |
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_STATUS_UTIL_H */ |
@ -1,51 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
/* Platform-independent features for gpr threads. */ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/gpr/thd.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
enum { GPR_THD_JOINABLE = 1 }; |
||||
|
||||
gpr_thd_options gpr_thd_options_default(void) { |
||||
gpr_thd_options options; |
||||
memset(&options, 0, sizeof(options)); |
||||
return options; |
||||
} |
||||
|
||||
void gpr_thd_options_set_detached(gpr_thd_options* options) { |
||||
options->flags &= ~GPR_THD_JOINABLE; |
||||
} |
||||
|
||||
void gpr_thd_options_set_joinable(gpr_thd_options* options) { |
||||
options->flags |= GPR_THD_JOINABLE; |
||||
} |
||||
|
||||
int gpr_thd_options_is_detached(const gpr_thd_options* options) { |
||||
if (!options) return 1; |
||||
return (options->flags & GPR_THD_JOINABLE) == 0; |
||||
} |
||||
|
||||
int gpr_thd_options_is_joinable(const gpr_thd_options* options) { |
||||
if (!options) return 0; |
||||
return (options->flags & GPR_THD_JOINABLE) == GPR_THD_JOINABLE; |
||||
} |
@ -1,72 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_LIB_GPR_THD_H |
||||
#define GRPC_CORE_LIB_GPR_THD_H |
||||
/** Internal thread interface for GPR.
|
||||
|
||||
Types |
||||
gpr_thd_options options used when creating a thread |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <grpc/support/thd_id.h> |
||||
#include <grpc/support/time.h> |
||||
|
||||
/** Thread creation options. */ |
||||
typedef struct { |
||||
int flags; /** Opaque field. Get and set with accessors below. */ |
||||
} gpr_thd_options; |
||||
|
||||
/** Create a new thread running (*thd_body)(arg) and place its thread identifier
|
||||
in *t, and return true. If there are insufficient resources, return false. |
||||
thd_name is the name of the thread for identification purposes on platforms |
||||
that support thread naming. |
||||
If options==NULL, default options are used. |
||||
The thread is immediately runnable, and exits when (*thd_body)() returns. */ |
||||
int gpr_thd_new(gpr_thd_id* t, const char* thd_name, |
||||
void (*thd_body)(void* arg), void* arg, |
||||
const gpr_thd_options* options); |
||||
|
||||
/** Return a gpr_thd_options struct with all fields set to defaults. */ |
||||
gpr_thd_options gpr_thd_options_default(void); |
||||
|
||||
/** Set the thread to become detached on startup - this is the default. */ |
||||
void gpr_thd_options_set_detached(gpr_thd_options* options); |
||||
|
||||
/** Set the thread to become joinable - mutually exclusive with detached. */ |
||||
void gpr_thd_options_set_joinable(gpr_thd_options* options); |
||||
|
||||
/** Returns non-zero if the option detached is set. */ |
||||
int gpr_thd_options_is_detached(const gpr_thd_options* options); |
||||
|
||||
/** Returns non-zero if the option joinable is set. */ |
||||
int gpr_thd_options_is_joinable(const gpr_thd_options* options); |
||||
|
||||
/** Blocks until the specified thread properly terminates.
|
||||
Calling this on a detached thread has unpredictable results. */ |
||||
void gpr_thd_join(gpr_thd_id t); |
||||
|
||||
/* Internal interfaces between modules within the gpr support library. */ |
||||
void gpr_thd_init(); |
||||
|
||||
/* Wait for all outstanding threads to finish, up to deadline */ |
||||
int gpr_await_threads(gpr_timespec deadline); |
||||
|
||||
#endif /* GRPC_CORE_LIB_GPR_THD_H */ |
@ -1,154 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
/* Posix implementation for gpr threads. */ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GPR_POSIX_SYNC |
||||
|
||||
#include "src/core/lib/gpr/thd.h" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/sync.h> |
||||
#include <grpc/support/thd_id.h> |
||||
#include <pthread.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
|
||||
#include "src/core/lib/gpr/fork.h" |
||||
#include "src/core/lib/gpr/useful.h" |
||||
|
||||
static gpr_mu g_mu; |
||||
static gpr_cv g_cv; |
||||
static int g_thread_count; |
||||
static int g_awaiting_threads; |
||||
|
||||
struct thd_arg { |
||||
void (*body)(void* arg); /* body of a thread */ |
||||
void* arg; /* argument to a thread */ |
||||
const char* name; /* name of thread. Can be nullptr. */ |
||||
}; |
||||
|
||||
static void inc_thd_count(); |
||||
static void dec_thd_count(); |
||||
|
||||
/* Body of every thread started via gpr_thd_new. */ |
||||
static void* thread_body(void* v) { |
||||
struct thd_arg a = *static_cast<struct thd_arg*>(v); |
||||
free(v); |
||||
if (a.name != nullptr) { |
||||
#if GPR_APPLE_PTHREAD_NAME |
||||
/* Apple supports 64 characters, and will truncate if it's longer. */ |
||||
pthread_setname_np(a.name); |
||||
#elif GPR_LINUX_PTHREAD_NAME |
||||
/* Linux supports 16 characters max, and will error if it's longer. */ |
||||
char buf[16]; |
||||
size_t buf_len = GPR_ARRAY_SIZE(buf) - 1; |
||||
strncpy(buf, a.name, buf_len); |
||||
buf[buf_len] = '\0'; |
||||
pthread_setname_np(pthread_self(), buf); |
||||
#endif // GPR_APPLE_PTHREAD_NAME
|
||||
} |
||||
(*a.body)(a.arg); |
||||
dec_thd_count(); |
||||
return nullptr; |
||||
} |
||||
|
||||
int gpr_thd_new(gpr_thd_id* t, const char* thd_name, |
||||
void (*thd_body)(void* arg), void* arg, |
||||
const gpr_thd_options* options) { |
||||
int thread_started; |
||||
pthread_attr_t attr; |
||||
pthread_t p; |
||||
/* don't use gpr_malloc as we may cause an infinite recursion with
|
||||
* the profiling code */ |
||||
struct thd_arg* a = static_cast<struct thd_arg*>(malloc(sizeof(*a))); |
||||
GPR_ASSERT(a != nullptr); |
||||
a->body = thd_body; |
||||
a->arg = arg; |
||||
a->name = thd_name; |
||||
inc_thd_count(); |
||||
|
||||
GPR_ASSERT(pthread_attr_init(&attr) == 0); |
||||
if (gpr_thd_options_is_detached(options)) { |
||||
GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == |
||||
0); |
||||
} else { |
||||
GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == |
||||
0); |
||||
} |
||||
thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0); |
||||
GPR_ASSERT(pthread_attr_destroy(&attr) == 0); |
||||
if (!thread_started) { |
||||
/* don't use gpr_free, as this was allocated using malloc (see above) */ |
||||
free(a); |
||||
dec_thd_count(); |
||||
} |
||||
*t = (gpr_thd_id)p; |
||||
return thread_started; |
||||
} |
||||
|
||||
gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); } |
||||
|
||||
void gpr_thd_join(gpr_thd_id t) { pthread_join((pthread_t)t, nullptr); } |
||||
|
||||
/*****************************************
|
||||
* Only used when fork support is enabled |
||||
*/ |
||||
|
||||
static void inc_thd_count() { |
||||
if (grpc_fork_support_enabled()) { |
||||
gpr_mu_lock(&g_mu); |
||||
g_thread_count++; |
||||
gpr_mu_unlock(&g_mu); |
||||
} |
||||
} |
||||
|
||||
static void dec_thd_count() { |
||||
if (grpc_fork_support_enabled()) { |
||||
gpr_mu_lock(&g_mu); |
||||
g_thread_count--; |
||||
if (g_awaiting_threads && g_thread_count == 0) { |
||||
gpr_cv_signal(&g_cv); |
||||
} |
||||
gpr_mu_unlock(&g_mu); |
||||
} |
||||
} |
||||
|
||||
void gpr_thd_init() { |
||||
gpr_mu_init(&g_mu); |
||||
gpr_cv_init(&g_cv); |
||||
g_thread_count = 0; |
||||
g_awaiting_threads = 0; |
||||
} |
||||
|
||||
int gpr_await_threads(gpr_timespec deadline) { |
||||
gpr_mu_lock(&g_mu); |
||||
g_awaiting_threads = 1; |
||||
int res = 0; |
||||
if (g_thread_count > 0) { |
||||
res = gpr_cv_wait(&g_cv, &g_mu, deadline); |
||||
} |
||||
g_awaiting_threads = 0; |
||||
gpr_mu_unlock(&g_mu); |
||||
return res == 0; |
||||
} |
||||
|
||||
#endif /* GPR_POSIX_SYNC */ |
@ -1,107 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
/* Windows implementation for gpr threads. */ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GPR_WINDOWS |
||||
|
||||
#include "src/core/lib/gpr/thd.h" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/thd_id.h> |
||||
#include <string.h> |
||||
|
||||
#if defined(_MSC_VER) |
||||
#define thread_local __declspec(thread) |
||||
#elif defined(__GNUC__) |
||||
#define thread_local __thread |
||||
#else |
||||
#error "Unknown compiler - please file a bug report" |
||||
#endif |
||||
|
||||
struct thd_info { |
||||
void (*body)(void* arg); /* body of a thread */ |
||||
void* arg; /* argument to a thread */ |
||||
HANDLE join_event; /* if joinable, the join event */ |
||||
int joinable; /* true if not detached */ |
||||
}; |
||||
|
||||
static thread_local struct thd_info* g_thd_info; |
||||
|
||||
/* Destroys a thread info */ |
||||
static void destroy_thread(struct thd_info* t) { |
||||
if (t->joinable) CloseHandle(t->join_event); |
||||
gpr_free(t); |
||||
} |
||||
|
||||
void gpr_thd_init(void) {} |
||||
|
||||
/* Body of every thread started via gpr_thd_new. */ |
||||
static DWORD WINAPI thread_body(void* v) { |
||||
g_thd_info = (struct thd_info*)v; |
||||
g_thd_info->body(g_thd_info->arg); |
||||
if (g_thd_info->joinable) { |
||||
BOOL ret = SetEvent(g_thd_info->join_event); |
||||
GPR_ASSERT(ret); |
||||
} else { |
||||
destroy_thread(g_thd_info); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
int gpr_thd_new(gpr_thd_id* t, const char* thd_name, |
||||
void (*thd_body)(void* arg), void* arg, |
||||
const gpr_thd_options* options) { |
||||
HANDLE handle; |
||||
struct thd_info* info = (struct thd_info*)gpr_malloc(sizeof(*info)); |
||||
info->body = thd_body; |
||||
info->arg = arg; |
||||
*t = 0; |
||||
if (gpr_thd_options_is_joinable(options)) { |
||||
info->joinable = 1; |
||||
info->join_event = CreateEvent(NULL, FALSE, FALSE, NULL); |
||||
if (info->join_event == NULL) { |
||||
gpr_free(info); |
||||
return 0; |
||||
} |
||||
} else { |
||||
info->joinable = 0; |
||||
} |
||||
handle = CreateThread(NULL, 64 * 1024, thread_body, info, 0, NULL); |
||||
if (handle == NULL) { |
||||
destroy_thread(info); |
||||
} else { |
||||
*t = (gpr_thd_id)info; |
||||
CloseHandle(handle); |
||||
} |
||||
return handle != NULL; |
||||
} |
||||
|
||||
gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; } |
||||
|
||||
void gpr_thd_join(gpr_thd_id t) { |
||||
struct thd_info* info = (struct thd_info*)t; |
||||
DWORD ret = WaitForSingleObject(info->join_event, INFINITE); |
||||
GPR_ASSERT(ret == WAIT_OBJECT_0); |
||||
destroy_thread(info); |
||||
} |
||||
|
||||
#endif /* GPR_WINDOWS */ |
@ -0,0 +1,135 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_LIB_GPRPP_THD_H |
||||
#define GRPC_CORE_LIB_GPRPP_THD_H |
||||
|
||||
/** Internal thread interface. */ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/sync.h> |
||||
#include <grpc/support/thd_id.h> |
||||
#include <grpc/support/time.h> |
||||
|
||||
#include "src/core/lib/gprpp/abstract.h" |
||||
#include "src/core/lib/gprpp/memory.h" |
||||
|
||||
namespace grpc_core { |
||||
namespace internal { |
||||
|
||||
/// Base class for platform-specific thread-state
|
||||
class ThreadInternalsInterface { |
||||
public: |
||||
virtual ~ThreadInternalsInterface() {} |
||||
virtual void Start() GRPC_ABSTRACT; |
||||
virtual void Join() GRPC_ABSTRACT; |
||||
GRPC_ABSTRACT_BASE_CLASS |
||||
}; |
||||
|
||||
} // namespace internal
|
||||
|
||||
class Thread { |
||||
public: |
||||
/// Default constructor only to allow use in structs that lack constructors
|
||||
/// Does not produce a validly-constructed thread; must later
|
||||
/// use placement new to construct a real thread. Does not init mu_ and cv_
|
||||
Thread() : state_(FAKE), impl_(nullptr) {} |
||||
|
||||
/// Normal constructor to create a thread with name \a thd_name,
|
||||
/// which will execute a thread based on function \a thd_body
|
||||
/// with argument \a arg once it is started.
|
||||
/// The optional \a success argument indicates whether the thread
|
||||
/// is successfully created.
|
||||
Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg, |
||||
bool* success = nullptr); |
||||
|
||||
/// Move constructor for thread. After this is called, the other thread
|
||||
/// no longer represents a living thread object
|
||||
Thread(Thread&& other) : state_(other.state_), impl_(other.impl_) { |
||||
other.state_ = MOVED; |
||||
other.impl_ = nullptr; |
||||
} |
||||
|
||||
/// Move assignment operator for thread. After this is called, the other
|
||||
/// thread no longer represents a living thread object. Not allowed if this
|
||||
/// thread actually exists
|
||||
Thread& operator=(Thread&& other) { |
||||
if (this != &other) { |
||||
// TODO(vjpai): if we can be sure that all Thread's are actually
|
||||
// constructed, then we should assert GPR_ASSERT(impl_ == nullptr) here.
|
||||
// However, as long as threads come in structures that are
|
||||
// allocated via gpr_malloc, this will not be the case, so we cannot
|
||||
// assert it for the time being.
|
||||
state_ = other.state_; |
||||
impl_ = other.impl_; |
||||
other.state_ = MOVED; |
||||
other.impl_ = nullptr; |
||||
} |
||||
return *this; |
||||
} |
||||
|
||||
/// The destructor is strictly optional; either the thread never came to life
|
||||
/// and the constructor itself killed it or it has already been joined and
|
||||
/// the Join function kills it. The destructor shouldn't have to do anything.
|
||||
~Thread() { GPR_ASSERT(impl_ == nullptr); } |
||||
|
||||
void Start() { |
||||
if (impl_ != nullptr) { |
||||
GPR_ASSERT(state_ == ALIVE); |
||||
state_ = STARTED; |
||||
impl_->Start(); |
||||
} else { |
||||
GPR_ASSERT(state_ == FAILED); |
||||
} |
||||
}; |
||||
|
||||
void Join() { |
||||
if (impl_ != nullptr) { |
||||
impl_->Join(); |
||||
grpc_core::Delete(impl_); |
||||
state_ = DONE; |
||||
impl_ = nullptr; |
||||
} else { |
||||
GPR_ASSERT(state_ == FAILED); |
||||
} |
||||
}; |
||||
|
||||
static void Init(); |
||||
static bool AwaitAll(gpr_timespec deadline); |
||||
|
||||
private: |
||||
Thread(const Thread&) = delete; |
||||
Thread& operator=(const Thread&) = delete; |
||||
|
||||
/// The thread states are as follows:
|
||||
/// FAKE -- just a dummy placeholder Thread created by the default constructor
|
||||
/// ALIVE -- an actual thread of control exists associated with this thread
|
||||
/// STARTED -- the thread of control has been started
|
||||
/// DONE -- the thread of control has completed and been joined
|
||||
/// FAILED -- the thread of control never came alive
|
||||
/// MOVED -- contents were moved out and we're no longer tracking them
|
||||
enum ThreadState { FAKE, ALIVE, STARTED, DONE, FAILED, MOVED }; |
||||
ThreadState state_; |
||||
internal::ThreadInternalsInterface* impl_; |
||||
}; |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_LIB_GPRPP_THD_H */ |
@ -0,0 +1,209 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
/* Posix implementation for gpr threads. */ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GPR_POSIX_SYNC |
||||
|
||||
#include "src/core/lib/gprpp/thd.h" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/sync.h> |
||||
#include <grpc/support/thd_id.h> |
||||
#include <pthread.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
|
||||
#include "src/core/lib/gpr/fork.h" |
||||
#include "src/core/lib/gpr/useful.h" |
||||
#include "src/core/lib/gprpp/memory.h" |
||||
|
||||
namespace grpc_core { |
||||
namespace { |
||||
gpr_mu g_mu; |
||||
gpr_cv g_cv; |
||||
int g_thread_count; |
||||
int g_awaiting_threads; |
||||
|
||||
class ThreadInternalsPosix; |
||||
struct thd_arg { |
||||
ThreadInternalsPosix* thread; |
||||
void (*body)(void* arg); /* body of a thread */ |
||||
void* arg; /* argument to a thread */ |
||||
const char* name; /* name of thread. Can be nullptr. */ |
||||
}; |
||||
|
||||
class ThreadInternalsPosix |
||||
: public grpc_core::internal::ThreadInternalsInterface { |
||||
public: |
||||
ThreadInternalsPosix(const char* thd_name, void (*thd_body)(void* arg), |
||||
void* arg, bool* success) |
||||
: started_(false) { |
||||
gpr_mu_init(&mu_); |
||||
gpr_cv_init(&ready_); |
||||
pthread_attr_t attr; |
||||
/* don't use gpr_malloc as we may cause an infinite recursion with
|
||||
* the profiling code */ |
||||
thd_arg* info = static_cast<thd_arg*>(malloc(sizeof(*info))); |
||||
GPR_ASSERT(info != nullptr); |
||||
info->thread = this; |
||||
info->body = thd_body; |
||||
info->arg = arg; |
||||
info->name = thd_name; |
||||
inc_thd_count(); |
||||
|
||||
GPR_ASSERT(pthread_attr_init(&attr) == 0); |
||||
GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == |
||||
0); |
||||
|
||||
*success = |
||||
(pthread_create(&pthread_id_, &attr, |
||||
[](void* v) -> void* { |
||||
thd_arg arg = *static_cast<thd_arg*>(v); |
||||
free(v); |
||||
if (arg.name != nullptr) { |
||||
#if GPR_APPLE_PTHREAD_NAME |
||||
/* Apple supports 64 characters, and will
|
||||
* truncate if it's longer. */ |
||||
pthread_setname_np(arg.name); |
||||
#elif GPR_LINUX_PTHREAD_NAME |
||||
/* Linux supports 16 characters max, and will
|
||||
* error if it's longer. */ |
||||
char buf[16]; |
||||
size_t buf_len = GPR_ARRAY_SIZE(buf) - 1; |
||||
strncpy(buf, arg.name, buf_len); |
||||
buf[buf_len] = '\0'; |
||||
pthread_setname_np(pthread_self(), buf); |
||||
#endif // GPR_APPLE_PTHREAD_NAME
|
||||
} |
||||
|
||||
gpr_mu_lock(&arg.thread->mu_); |
||||
while (!arg.thread->started_) { |
||||
gpr_cv_wait(&arg.thread->ready_, &arg.thread->mu_, |
||||
gpr_inf_future(GPR_CLOCK_MONOTONIC)); |
||||
} |
||||
gpr_mu_unlock(&arg.thread->mu_); |
||||
|
||||
(*arg.body)(arg.arg); |
||||
dec_thd_count(); |
||||
return nullptr; |
||||
}, |
||||
info) == 0); |
||||
|
||||
GPR_ASSERT(pthread_attr_destroy(&attr) == 0); |
||||
|
||||
if (!success) { |
||||
/* don't use gpr_free, as this was allocated using malloc (see above) */ |
||||
free(info); |
||||
dec_thd_count(); |
||||
} |
||||
}; |
||||
|
||||
~ThreadInternalsPosix() override { |
||||
gpr_mu_destroy(&mu_); |
||||
gpr_cv_destroy(&ready_); |
||||
} |
||||
|
||||
void Start() override { |
||||
gpr_mu_lock(&mu_); |
||||
started_ = true; |
||||
gpr_cv_signal(&ready_); |
||||
gpr_mu_unlock(&mu_); |
||||
} |
||||
|
||||
void Join() override { pthread_join(pthread_id_, nullptr); } |
||||
|
||||
private: |
||||
/*****************************************
|
||||
* Only used when fork support is enabled |
||||
*/ |
||||
|
||||
static void inc_thd_count() { |
||||
if (grpc_fork_support_enabled()) { |
||||
gpr_mu_lock(&g_mu); |
||||
g_thread_count++; |
||||
gpr_mu_unlock(&g_mu); |
||||
} |
||||
} |
||||
|
||||
static void dec_thd_count() { |
||||
if (grpc_fork_support_enabled()) { |
||||
gpr_mu_lock(&g_mu); |
||||
g_thread_count--; |
||||
if (g_awaiting_threads && g_thread_count == 0) { |
||||
gpr_cv_signal(&g_cv); |
||||
} |
||||
gpr_mu_unlock(&g_mu); |
||||
} |
||||
} |
||||
|
||||
gpr_mu mu_; |
||||
gpr_cv ready_; |
||||
bool started_; |
||||
pthread_t pthread_id_; |
||||
}; |
||||
|
||||
} // namespace
|
||||
|
||||
Thread::Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg, |
||||
bool* success) { |
||||
bool outcome = false; |
||||
impl_ = |
||||
grpc_core::New<ThreadInternalsPosix>(thd_name, thd_body, arg, &outcome); |
||||
if (outcome) { |
||||
state_ = ALIVE; |
||||
} else { |
||||
state_ = FAILED; |
||||
grpc_core::Delete(impl_); |
||||
impl_ = nullptr; |
||||
} |
||||
|
||||
if (success != nullptr) { |
||||
*success = outcome; |
||||
} |
||||
} |
||||
|
||||
void Thread::Init() { |
||||
gpr_mu_init(&g_mu); |
||||
gpr_cv_init(&g_cv); |
||||
g_thread_count = 0; |
||||
g_awaiting_threads = 0; |
||||
} |
||||
|
||||
bool Thread::AwaitAll(gpr_timespec deadline) { |
||||
gpr_mu_lock(&g_mu); |
||||
g_awaiting_threads = 1; |
||||
int res = 0; |
||||
while ((g_thread_count > 0) && |
||||
(gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0)) { |
||||
res = gpr_cv_wait(&g_cv, &g_mu, deadline); |
||||
} |
||||
g_awaiting_threads = 0; |
||||
gpr_mu_unlock(&g_mu); |
||||
return res == 0; |
||||
} |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
// The following is in the external namespace as it is exposed as C89 API
|
||||
gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); } |
||||
|
||||
#endif /* GPR_POSIX_SYNC */ |
@ -0,0 +1,162 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
/* Windows implementation for gpr threads. */ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GPR_WINDOWS |
||||
|
||||
#include "src/core/lib/gprpp/thd.h" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/thd_id.h> |
||||
#include <string.h> |
||||
|
||||
#include "src/core/lib/gprpp/memory.h" |
||||
|
||||
#if defined(_MSC_VER) |
||||
#define thread_local __declspec(thread) |
||||
#define WIN_LAMBDA |
||||
#elif defined(__GNUC__) |
||||
#define thread_local __thread |
||||
#define WIN_LAMBDA WINAPI |
||||
#else |
||||
#error "Unknown compiler - please file a bug report" |
||||
#endif |
||||
|
||||
namespace { |
||||
class ThreadInternalsWindows; |
||||
struct thd_info { |
||||
ThreadInternalsWindows* thread; |
||||
void (*body)(void* arg); /* body of a thread */ |
||||
void* arg; /* argument to a thread */ |
||||
HANDLE join_event; /* the join event */ |
||||
}; |
||||
|
||||
thread_local struct thd_info* g_thd_info; |
||||
|
||||
class ThreadInternalsWindows |
||||
: public grpc_core::internal::ThreadInternalsInterface { |
||||
public: |
||||
ThreadInternalsWindows(void (*thd_body)(void* arg), void* arg, bool* success) |
||||
: started_(false) { |
||||
gpr_mu_init(&mu_); |
||||
gpr_cv_init(&ready_); |
||||
|
||||
HANDLE handle; |
||||
info_ = (struct thd_info*)gpr_malloc(sizeof(*info_)); |
||||
info_->thread = this; |
||||
info_->body = thd_body; |
||||
info_->arg = arg; |
||||
|
||||
info_->join_event = CreateEvent(nullptr, FALSE, FALSE, nullptr); |
||||
if (info_->join_event == nullptr) { |
||||
gpr_free(info_); |
||||
*success = false; |
||||
} else { |
||||
handle = CreateThread( |
||||
nullptr, 64 * 1024, |
||||
[](void* v) WIN_LAMBDA -> DWORD { |
||||
g_thd_info = static_cast<thd_info*>(v); |
||||
gpr_mu_lock(&g_thd_info->thread->mu_); |
||||
while (!g_thd_info->thread->started_) { |
||||
gpr_cv_wait(&g_thd_info->thread->ready_, &g_thd_info->thread->mu_, |
||||
gpr_inf_future(GPR_CLOCK_MONOTONIC)); |
||||
} |
||||
gpr_mu_unlock(&g_thd_info->thread->mu_); |
||||
g_thd_info->body(g_thd_info->arg); |
||||
BOOL ret = SetEvent(g_thd_info->join_event); |
||||
GPR_ASSERT(ret); |
||||
return 0; |
||||
}, |
||||
info_, 0, nullptr); |
||||
if (handle == nullptr) { |
||||
destroy_thread(); |
||||
*success = false; |
||||
} else { |
||||
CloseHandle(handle); |
||||
*success = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
~ThreadInternalsWindows() override { |
||||
gpr_mu_destroy(&mu_); |
||||
gpr_cv_destroy(&ready_); |
||||
} |
||||
|
||||
void Start() override { |
||||
gpr_mu_lock(&mu_); |
||||
started_ = true; |
||||
gpr_cv_signal(&ready_); |
||||
gpr_mu_unlock(&mu_); |
||||
} |
||||
|
||||
void Join() override { |
||||
DWORD ret = WaitForSingleObject(info_->join_event, INFINITE); |
||||
GPR_ASSERT(ret == WAIT_OBJECT_0); |
||||
destroy_thread(); |
||||
} |
||||
|
||||
private: |
||||
void destroy_thread() { |
||||
CloseHandle(info_->join_event); |
||||
gpr_free(info_); |
||||
} |
||||
|
||||
gpr_mu mu_; |
||||
gpr_cv ready_; |
||||
bool started_; |
||||
thd_info* info_; |
||||
}; |
||||
|
||||
} // namespace
|
||||
|
||||
namespace grpc_core { |
||||
|
||||
void Thread::Init() {} |
||||
|
||||
bool Thread::AwaitAll(gpr_timespec deadline) { |
||||
// TODO: Consider adding this if needed
|
||||
return false; |
||||
} |
||||
|
||||
Thread::Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg, |
||||
bool* success) { |
||||
bool outcome = false; |
||||
impl_ = grpc_core::New<ThreadInternalsWindows>(thd_body, arg, &outcome); |
||||
if (outcome) { |
||||
state_ = ALIVE; |
||||
} else { |
||||
state_ = FAILED; |
||||
grpc_core::Delete(impl_); |
||||
impl_ = nullptr; |
||||
} |
||||
|
||||
if (success != nullptr) { |
||||
*success = outcome; |
||||
} |
||||
} |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; } |
||||
|
||||
#endif /* GPR_WINDOWS */ |
@ -0,0 +1,105 @@ |
||||
/*
|
||||
* Copyright 2016 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_LIB_SLICE_SLICE_WEAK_HASH_TABLE_H |
||||
#define GRPC_CORE_LIB_SLICE_SLICE_WEAK_HASH_TABLE_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/gprpp/memory.h" |
||||
#include "src/core/lib/gprpp/ref_counted.h" |
||||
#include "src/core/lib/gprpp/ref_counted_ptr.h" |
||||
#include "src/core/lib/slice/slice_internal.h" |
||||
|
||||
/// Weak hash table implementation.
|
||||
///
|
||||
/// This entries in this table are weak: an entry may be removed at any time due
|
||||
/// to a number of reasons: memory pressure, hash collisions, etc.
|
||||
///
|
||||
/// The keys are \a grpc_slice objects. The values are of arbitrary type.
|
||||
///
|
||||
/// This class is thread unsafe. It's the caller's responsibility to ensure
|
||||
/// proper locking when accessing its methods.
|
||||
|
||||
namespace grpc_core { |
||||
|
||||
template <typename T, size_t Size> |
||||
class SliceWeakHashTable : public RefCounted<SliceWeakHashTable<T, Size>> { |
||||
public: |
||||
/// Creates a new table of at most \a size entries.
|
||||
static RefCountedPtr<SliceWeakHashTable> Create() { |
||||
return MakeRefCounted<SliceWeakHashTable<T, Size>>(); |
||||
} |
||||
|
||||
/// Add a mapping from \a key to \a value, taking ownership of \a key. This
|
||||
/// operation will always succeed. It may discard older entries.
|
||||
void Add(grpc_slice key, T value) { |
||||
const size_t idx = grpc_slice_hash(key) % Size; |
||||
entries_[idx].Set(key, std::move(value)); |
||||
return; |
||||
} |
||||
|
||||
/// Returns the value from the table associated with / \a key or null if not
|
||||
/// found.
|
||||
const T* Get(const grpc_slice key) const { |
||||
const size_t idx = grpc_slice_hash(key) % Size; |
||||
const auto& entry = entries_[idx]; |
||||
return grpc_slice_eq(entry.key(), key) ? entry.value() : nullptr; |
||||
} |
||||
|
||||
private: |
||||
// So New() can call our private ctor.
|
||||
template <typename T2, typename... Args> |
||||
friend T2* New(Args&&... args); |
||||
|
||||
SliceWeakHashTable() = default; |
||||
~SliceWeakHashTable() = default; |
||||
|
||||
/// The type of the table "rows".
|
||||
class Entry { |
||||
public: |
||||
Entry() = default; |
||||
~Entry() { |
||||
if (is_set_) grpc_slice_unref_internal(key_); |
||||
} |
||||
grpc_slice key() const { return key_; } |
||||
|
||||
/// Return the entry's value, or null if unset.
|
||||
const T* value() const { |
||||
if (!is_set_) return nullptr; |
||||
return &value_; |
||||
} |
||||
|
||||
/// Set the \a key and \a value (which is moved) for the entry.
|
||||
void Set(grpc_slice key, T&& value) { |
||||
if (is_set_) grpc_slice_unref_internal(key_); |
||||
key_ = key; |
||||
value_ = std::move(value); |
||||
is_set_ = true; |
||||
} |
||||
|
||||
private: |
||||
grpc_slice key_; |
||||
T value_; |
||||
bool is_set_ = false; |
||||
}; |
||||
|
||||
Entry entries_[Size]; |
||||
}; |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_LIB_SLICE_SLICE_WEAK_HASH_TABLE_H */ |
@ -0,0 +1,54 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2017 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/transport/status_metadata.h" |
||||
|
||||
#include "src/core/lib/slice/slice_string_helpers.h" |
||||
#include "src/core/lib/transport/static_metadata.h" |
||||
|
||||
/* we offset status by a small amount when storing it into transport metadata
|
||||
as metadata cannot store a 0 value (which is used as OK for grpc_status_codes |
||||
*/ |
||||
#define STATUS_OFFSET 1 |
||||
|
||||
static void destroy_status(void* ignored) {} |
||||
|
||||
grpc_status_code grpc_get_status_code_from_metadata(grpc_mdelem md) { |
||||
if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) { |
||||
return GRPC_STATUS_OK; |
||||
} |
||||
if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_1)) { |
||||
return GRPC_STATUS_CANCELLED; |
||||
} |
||||
if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_2)) { |
||||
return GRPC_STATUS_UNKNOWN; |
||||
} |
||||
void* user_data = grpc_mdelem_get_user_data(md, destroy_status); |
||||
if (user_data != nullptr) { |
||||
return static_cast<grpc_status_code>((intptr_t)user_data - STATUS_OFFSET); |
||||
} |
||||
uint32_t status; |
||||
if (!grpc_parse_slice_to_uint32(GRPC_MDVALUE(md), &status)) { |
||||
status = GRPC_STATUS_UNKNOWN; /* could not parse status code */ |
||||
} |
||||
grpc_mdelem_set_user_data( |
||||
md, destroy_status, (void*)static_cast<intptr_t>(status + STATUS_OFFSET)); |
||||
return static_cast<grpc_status_code>(status); |
||||
} |
@ -0,0 +1,30 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2017 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_LIB_TRANSPORT_STATUS_METADATA_H |
||||
#define GRPC_CORE_LIB_TRANSPORT_STATUS_METADATA_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <grpc/status.h> |
||||
|
||||
#include "src/core/lib/transport/metadata.h" |
||||
|
||||
grpc_status_code grpc_get_status_code_from_metadata(grpc_mdelem md); |
||||
|
||||
#endif /* GRPC_CORE_LIB_TRANSPORT_STATUS_METADATA_H */ |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue