xref: /aosp_15_r20/external/aws-crt-java/src/native/event_loop_group.c (revision 3c7ae9de214676c52d19f01067dc1a404272dc11)
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