1*3c7ae9deSAndroid Build Coastguard Worker /**
2*3c7ae9deSAndroid Build Coastguard Worker * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3*3c7ae9deSAndroid Build Coastguard Worker * SPDX-License-Identifier: Apache-2.0.
4*3c7ae9deSAndroid Build Coastguard Worker */
5*3c7ae9deSAndroid Build Coastguard Worker
6*3c7ae9deSAndroid Build Coastguard Worker #include <jni.h>
7*3c7ae9deSAndroid Build Coastguard Worker
8*3c7ae9deSAndroid Build Coastguard Worker #include <aws/io/event_loop.h>
9*3c7ae9deSAndroid Build Coastguard Worker #include <aws/io/logging.h>
10*3c7ae9deSAndroid Build Coastguard Worker
11*3c7ae9deSAndroid Build Coastguard Worker #include "crt.h"
12*3c7ae9deSAndroid Build Coastguard Worker #include "java_class_ids.h"
13*3c7ae9deSAndroid Build Coastguard Worker
14*3c7ae9deSAndroid Build Coastguard Worker #if _MSC_VER
15*3c7ae9deSAndroid Build Coastguard Worker # pragma warning(disable : 4204) /* non-constant aggregate initializer */
16*3c7ae9deSAndroid Build Coastguard Worker #endif
17*3c7ae9deSAndroid Build Coastguard Worker
18*3c7ae9deSAndroid Build Coastguard Worker /* on 32-bit platforms, casting pointers to longs throws a warning we don't need */
19*3c7ae9deSAndroid Build Coastguard Worker #if UINTPTR_MAX == 0xffffffff
20*3c7ae9deSAndroid Build Coastguard Worker # if defined(_MSC_VER)
21*3c7ae9deSAndroid Build Coastguard Worker # pragma warning(push)
22*3c7ae9deSAndroid Build Coastguard Worker # pragma warning(disable : 4305) /* 'type cast': truncation from 'jlong' to 'jni_tls_ctx_options *' */
23*3c7ae9deSAndroid Build Coastguard Worker # else
24*3c7ae9deSAndroid Build Coastguard Worker # pragma GCC diagnostic push
25*3c7ae9deSAndroid Build Coastguard Worker # pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
26*3c7ae9deSAndroid Build Coastguard Worker # pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
27*3c7ae9deSAndroid Build Coastguard Worker # endif
28*3c7ae9deSAndroid Build Coastguard Worker #endif
29*3c7ae9deSAndroid Build Coastguard Worker
30*3c7ae9deSAndroid Build Coastguard Worker struct event_loop_group_cleanup_callback_data {
31*3c7ae9deSAndroid Build Coastguard Worker JavaVM *jvm;
32*3c7ae9deSAndroid Build Coastguard Worker jobject java_event_loop_group;
33*3c7ae9deSAndroid Build Coastguard Worker };
34*3c7ae9deSAndroid Build Coastguard Worker
s_event_loop_group_cleanup_completion_callback(void * user_data)35*3c7ae9deSAndroid Build Coastguard Worker static void s_event_loop_group_cleanup_completion_callback(void *user_data) {
36*3c7ae9deSAndroid Build Coastguard Worker struct event_loop_group_cleanup_callback_data *callback_data = user_data;
37*3c7ae9deSAndroid Build Coastguard Worker
38*3c7ae9deSAndroid Build Coastguard Worker AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Event Loop Shutdown Complete");
39*3c7ae9deSAndroid Build Coastguard Worker
40*3c7ae9deSAndroid Build Coastguard Worker // Tell the Java event loop group that cleanup is done. This lets it release its references.
41*3c7ae9deSAndroid Build Coastguard Worker JavaVM *jvm = callback_data->jvm;
42*3c7ae9deSAndroid Build Coastguard Worker JNIEnv *env = NULL;
43*3c7ae9deSAndroid Build Coastguard Worker /* fetch the env manually, rather than through the helper which will install an exit callback */
44*3c7ae9deSAndroid Build Coastguard Worker #ifdef ANDROID
45*3c7ae9deSAndroid Build Coastguard Worker (*jvm)->AttachCurrentThread(jvm, &env, NULL);
46*3c7ae9deSAndroid Build Coastguard Worker #else
47*3c7ae9deSAndroid Build Coastguard Worker /* awkward temp to get around gcc 4.1 strict aliasing incorrect warnings */
48*3c7ae9deSAndroid Build Coastguard Worker void *temp_env = NULL;
49*3c7ae9deSAndroid Build Coastguard Worker (*jvm)->AttachCurrentThread(jvm, (void **)&temp_env, NULL);
50*3c7ae9deSAndroid Build Coastguard Worker env = temp_env;
51*3c7ae9deSAndroid Build Coastguard Worker #endif
52*3c7ae9deSAndroid Build Coastguard Worker
53*3c7ae9deSAndroid Build Coastguard Worker /*
54*3c7ae9deSAndroid Build Coastguard Worker * The likely cause of env being null is the JVM shutting down before our stuff completely shuts down. In that
55*3c7ae9deSAndroid Build Coastguard Worker * case, let's not even free memory. This is most likely a consequence of a "failed" gentle shutdown so all
56*3c7ae9deSAndroid Build Coastguard Worker * the library clean up and allocator/logging clean up wont get called, but let's not even take that risk.
57*3c7ae9deSAndroid Build Coastguard Worker */
58*3c7ae9deSAndroid Build Coastguard Worker if (env != NULL) {
59*3c7ae9deSAndroid Build Coastguard Worker (*env)->CallVoidMethod(
60*3c7ae9deSAndroid Build Coastguard Worker env, callback_data->java_event_loop_group, event_loop_group_properties.onCleanupComplete);
61*3c7ae9deSAndroid Build Coastguard Worker AWS_FATAL_ASSERT(!aws_jni_check_and_clear_exception(env));
62*3c7ae9deSAndroid Build Coastguard Worker
63*3c7ae9deSAndroid Build Coastguard Worker // Remove the ref that was probably keeping the Java event loop group alive.
64*3c7ae9deSAndroid Build Coastguard Worker (*env)->DeleteGlobalRef(env, callback_data->java_event_loop_group);
65*3c7ae9deSAndroid Build Coastguard Worker
66*3c7ae9deSAndroid Build Coastguard Worker // We're done with this callback data, free it.
67*3c7ae9deSAndroid Build Coastguard Worker struct aws_allocator *allocator = aws_jni_get_allocator();
68*3c7ae9deSAndroid Build Coastguard Worker aws_mem_release(allocator, callback_data);
69*3c7ae9deSAndroid Build Coastguard Worker
70*3c7ae9deSAndroid Build Coastguard Worker (*jvm)->DetachCurrentThread(jvm);
71*3c7ae9deSAndroid Build Coastguard Worker }
72*3c7ae9deSAndroid Build Coastguard Worker }
73*3c7ae9deSAndroid Build Coastguard Worker
74*3c7ae9deSAndroid Build Coastguard Worker JNIEXPORT
Java_software_amazon_awssdk_crt_io_EventLoopGroup_eventLoopGroupNew(JNIEnv * env,jclass jni_elg,jobject elg_jobject,jint num_threads)75*3c7ae9deSAndroid Build Coastguard Worker jlong JNICALL Java_software_amazon_awssdk_crt_io_EventLoopGroup_eventLoopGroupNew(
76*3c7ae9deSAndroid Build Coastguard Worker JNIEnv *env,
77*3c7ae9deSAndroid Build Coastguard Worker jclass jni_elg,
78*3c7ae9deSAndroid Build Coastguard Worker jobject elg_jobject,
79*3c7ae9deSAndroid Build Coastguard Worker jint num_threads) {
80*3c7ae9deSAndroid Build Coastguard Worker (void)jni_elg;
81*3c7ae9deSAndroid Build Coastguard Worker aws_cache_jni_ids(env);
82*3c7ae9deSAndroid Build Coastguard Worker
83*3c7ae9deSAndroid Build Coastguard Worker struct aws_allocator *allocator = aws_jni_get_allocator();
84*3c7ae9deSAndroid Build Coastguard Worker
85*3c7ae9deSAndroid Build Coastguard Worker struct event_loop_group_cleanup_callback_data *callback_data =
86*3c7ae9deSAndroid Build Coastguard Worker aws_mem_acquire(allocator, sizeof(struct event_loop_group_cleanup_callback_data));
87*3c7ae9deSAndroid Build Coastguard Worker if (callback_data == NULL) {
88*3c7ae9deSAndroid Build Coastguard Worker aws_jni_throw_runtime_exception(
89*3c7ae9deSAndroid Build Coastguard Worker env, "EventLoopGroup.event_loop_group_new: shutdown callback data allocation failed");
90*3c7ae9deSAndroid Build Coastguard Worker goto on_error;
91*3c7ae9deSAndroid Build Coastguard Worker }
92*3c7ae9deSAndroid Build Coastguard Worker
93*3c7ae9deSAndroid Build Coastguard Worker jint jvmresult = (*env)->GetJavaVM(env, &callback_data->jvm);
94*3c7ae9deSAndroid Build Coastguard Worker AWS_FATAL_ASSERT(jvmresult == 0);
95*3c7ae9deSAndroid Build Coastguard Worker
96*3c7ae9deSAndroid Build Coastguard Worker struct aws_shutdown_callback_options shutdown_options = {
97*3c7ae9deSAndroid Build Coastguard Worker .shutdown_callback_fn = s_event_loop_group_cleanup_completion_callback,
98*3c7ae9deSAndroid Build Coastguard Worker .shutdown_callback_user_data = callback_data,
99*3c7ae9deSAndroid Build Coastguard Worker };
100*3c7ae9deSAndroid Build Coastguard Worker
101*3c7ae9deSAndroid Build Coastguard Worker struct aws_event_loop_group *elg =
102*3c7ae9deSAndroid Build Coastguard Worker aws_event_loop_group_new_default(allocator, (uint16_t)num_threads, &shutdown_options);
103*3c7ae9deSAndroid Build Coastguard Worker if (elg == NULL) {
104*3c7ae9deSAndroid Build Coastguard Worker aws_jni_throw_runtime_exception(
105*3c7ae9deSAndroid Build Coastguard Worker env, "EventLoopGroup.event_loop_group_new: aws_event_loop_group_new_default failed");
106*3c7ae9deSAndroid Build Coastguard Worker goto on_error;
107*3c7ae9deSAndroid Build Coastguard Worker }
108*3c7ae9deSAndroid Build Coastguard Worker
109*3c7ae9deSAndroid Build Coastguard Worker callback_data->java_event_loop_group = (*env)->NewGlobalRef(env, elg_jobject);
110*3c7ae9deSAndroid Build Coastguard Worker
111*3c7ae9deSAndroid Build Coastguard Worker return (jlong)elg;
112*3c7ae9deSAndroid Build Coastguard Worker
113*3c7ae9deSAndroid Build Coastguard Worker on_error:
114*3c7ae9deSAndroid Build Coastguard Worker
115*3c7ae9deSAndroid Build Coastguard Worker aws_mem_release(allocator, callback_data);
116*3c7ae9deSAndroid Build Coastguard Worker
117*3c7ae9deSAndroid Build Coastguard Worker return (jlong)NULL;
118*3c7ae9deSAndroid Build Coastguard Worker }
119*3c7ae9deSAndroid Build Coastguard Worker
120*3c7ae9deSAndroid Build Coastguard Worker JNIEXPORT
Java_software_amazon_awssdk_crt_io_EventLoopGroup_eventLoopGroupNewPinnedToCpuGroup(JNIEnv * env,jclass jni_elg,jobject elg_jobject,jint cpu_group,jint num_threads)121*3c7ae9deSAndroid Build Coastguard Worker jlong JNICALL Java_software_amazon_awssdk_crt_io_EventLoopGroup_eventLoopGroupNewPinnedToCpuGroup(
122*3c7ae9deSAndroid Build Coastguard Worker JNIEnv *env,
123*3c7ae9deSAndroid Build Coastguard Worker jclass jni_elg,
124*3c7ae9deSAndroid Build Coastguard Worker jobject elg_jobject,
125*3c7ae9deSAndroid Build Coastguard Worker jint cpu_group,
126*3c7ae9deSAndroid Build Coastguard Worker jint num_threads) {
127*3c7ae9deSAndroid Build Coastguard Worker (void)jni_elg;
128*3c7ae9deSAndroid Build Coastguard Worker aws_cache_jni_ids(env);
129*3c7ae9deSAndroid Build Coastguard Worker
130*3c7ae9deSAndroid Build Coastguard Worker struct aws_allocator *allocator = aws_jni_get_allocator();
131*3c7ae9deSAndroid Build Coastguard Worker
132*3c7ae9deSAndroid Build Coastguard Worker struct event_loop_group_cleanup_callback_data *callback_data =
133*3c7ae9deSAndroid Build Coastguard Worker aws_mem_acquire(allocator, sizeof(struct event_loop_group_cleanup_callback_data));
134*3c7ae9deSAndroid Build Coastguard Worker if (callback_data == NULL) {
135*3c7ae9deSAndroid Build Coastguard Worker aws_jni_throw_runtime_exception(
136*3c7ae9deSAndroid Build Coastguard Worker env, "EventLoopGroup.event_loop_group_new: shutdown callback data allocation failed");
137*3c7ae9deSAndroid Build Coastguard Worker goto on_error;
138*3c7ae9deSAndroid Build Coastguard Worker }
139*3c7ae9deSAndroid Build Coastguard Worker
140*3c7ae9deSAndroid Build Coastguard Worker jint jvmresult = (*env)->GetJavaVM(env, &callback_data->jvm);
141*3c7ae9deSAndroid Build Coastguard Worker AWS_FATAL_ASSERT(jvmresult == 0);
142*3c7ae9deSAndroid Build Coastguard Worker
143*3c7ae9deSAndroid Build Coastguard Worker struct aws_shutdown_callback_options shutdown_options = {
144*3c7ae9deSAndroid Build Coastguard Worker .shutdown_callback_fn = s_event_loop_group_cleanup_completion_callback,
145*3c7ae9deSAndroid Build Coastguard Worker .shutdown_callback_user_data = callback_data,
146*3c7ae9deSAndroid Build Coastguard Worker };
147*3c7ae9deSAndroid Build Coastguard Worker
148*3c7ae9deSAndroid Build Coastguard Worker struct aws_event_loop_group *elg = aws_event_loop_group_new_default_pinned_to_cpu_group(
149*3c7ae9deSAndroid Build Coastguard Worker allocator, (uint16_t)num_threads, (uint16_t)cpu_group, &shutdown_options);
150*3c7ae9deSAndroid Build Coastguard Worker if (elg == NULL) {
151*3c7ae9deSAndroid Build Coastguard Worker aws_jni_throw_runtime_exception(
152*3c7ae9deSAndroid Build Coastguard Worker env, "EventLoopGroup.event_loop_group_new: eventLoopGroupNewPinnedToCpuGroup failed");
153*3c7ae9deSAndroid Build Coastguard Worker goto on_error;
154*3c7ae9deSAndroid Build Coastguard Worker }
155*3c7ae9deSAndroid Build Coastguard Worker
156*3c7ae9deSAndroid Build Coastguard Worker callback_data->java_event_loop_group = (*env)->NewGlobalRef(env, elg_jobject);
157*3c7ae9deSAndroid Build Coastguard Worker
158*3c7ae9deSAndroid Build Coastguard Worker return (jlong)elg;
159*3c7ae9deSAndroid Build Coastguard Worker
160*3c7ae9deSAndroid Build Coastguard Worker on_error:
161*3c7ae9deSAndroid Build Coastguard Worker
162*3c7ae9deSAndroid Build Coastguard Worker aws_mem_release(allocator, callback_data);
163*3c7ae9deSAndroid Build Coastguard Worker
164*3c7ae9deSAndroid Build Coastguard Worker return (jlong)NULL;
165*3c7ae9deSAndroid Build Coastguard Worker }
166*3c7ae9deSAndroid Build Coastguard Worker
167*3c7ae9deSAndroid Build Coastguard Worker JNIEXPORT
Java_software_amazon_awssdk_crt_io_EventLoopGroup_eventLoopGroupDestroy(JNIEnv * env,jclass jni_elg,jlong elg_addr)168*3c7ae9deSAndroid Build Coastguard Worker void JNICALL Java_software_amazon_awssdk_crt_io_EventLoopGroup_eventLoopGroupDestroy(
169*3c7ae9deSAndroid Build Coastguard Worker JNIEnv *env,
170*3c7ae9deSAndroid Build Coastguard Worker jclass jni_elg,
171*3c7ae9deSAndroid Build Coastguard Worker jlong elg_addr) {
172*3c7ae9deSAndroid Build Coastguard Worker (void)jni_elg;
173*3c7ae9deSAndroid Build Coastguard Worker aws_cache_jni_ids(env);
174*3c7ae9deSAndroid Build Coastguard Worker
175*3c7ae9deSAndroid Build Coastguard Worker struct aws_event_loop_group *elg = (struct aws_event_loop_group *)elg_addr;
176*3c7ae9deSAndroid Build Coastguard Worker if (!elg) {
177*3c7ae9deSAndroid Build Coastguard Worker aws_jni_throw_runtime_exception(
178*3c7ae9deSAndroid Build Coastguard Worker env, "EventLoopGroup.eventLoopGroupDestroy: instance should be non-null at release time");
179*3c7ae9deSAndroid Build Coastguard Worker return;
180*3c7ae9deSAndroid Build Coastguard Worker }
181*3c7ae9deSAndroid Build Coastguard Worker
182*3c7ae9deSAndroid Build Coastguard Worker aws_event_loop_group_release(elg);
183*3c7ae9deSAndroid Build Coastguard Worker }
184*3c7ae9deSAndroid Build Coastguard Worker
185*3c7ae9deSAndroid Build Coastguard Worker #if UINTPTR_MAX == 0xffffffff
186*3c7ae9deSAndroid Build Coastguard Worker # if defined(_MSC_VER)
187*3c7ae9deSAndroid Build Coastguard Worker # pragma warning(pop)
188*3c7ae9deSAndroid Build Coastguard Worker # else
189*3c7ae9deSAndroid Build Coastguard Worker # pragma GCC diagnostic pop
190*3c7ae9deSAndroid Build Coastguard Worker # endif
191*3c7ae9deSAndroid Build Coastguard Worker #endif
192