1977Smax.romanov@gmail.com 2977Smax.romanov@gmail.com /* 3977Smax.romanov@gmail.com * Copyright (C) NGINX, Inc. 4977Smax.romanov@gmail.com */ 5977Smax.romanov@gmail.com 6977Smax.romanov@gmail.com 7977Smax.romanov@gmail.com #include <jni.h> 8977Smax.romanov@gmail.com 9977Smax.romanov@gmail.com #include <nxt_main.h> 10977Smax.romanov@gmail.com #include <nxt_runtime.h> 11977Smax.romanov@gmail.com #include <nxt_router.h> 12977Smax.romanov@gmail.com #include <nxt_unit.h> 13977Smax.romanov@gmail.com #include <nxt_unit_field.h> 14977Smax.romanov@gmail.com #include <nxt_unit_request.h> 15977Smax.romanov@gmail.com #include <nxt_unit_response.h> 161157Smax.romanov@nginx.com #include <nxt_unit_websocket.h> 17977Smax.romanov@gmail.com 18977Smax.romanov@gmail.com #include <java/nxt_jni.h> 19977Smax.romanov@gmail.com 20977Smax.romanov@gmail.com #include "java/nxt_jni_Thread.h" 21977Smax.romanov@gmail.com #include "java/nxt_jni_Context.h" 22977Smax.romanov@gmail.com #include "java/nxt_jni_Request.h" 23977Smax.romanov@gmail.com #include "java/nxt_jni_Response.h" 24977Smax.romanov@gmail.com #include "java/nxt_jni_InputStream.h" 25977Smax.romanov@gmail.com #include "java/nxt_jni_OutputStream.h" 26977Smax.romanov@gmail.com #include "java/nxt_jni_URLClassLoader.h" 27977Smax.romanov@gmail.com 28977Smax.romanov@gmail.com #include "nxt_jars.h" 291532St.nateldemoura@f5.com 301532St.nateldemoura@f5.com #include NXT_JAVA_MOUNTS_H 31977Smax.romanov@gmail.com 321488St.nateldemoura@f5.com static nxt_int_t nxt_java_setup(nxt_task_t *task, nxt_process_t *process, 33977Smax.romanov@gmail.com nxt_common_app_conf_t *conf); 341488St.nateldemoura@f5.com static nxt_int_t nxt_java_start(nxt_task_t *task, 351488St.nateldemoura@f5.com nxt_process_data_t *data); 36977Smax.romanov@gmail.com static void nxt_java_request_handler(nxt_unit_request_info_t *req); 371157Smax.romanov@nginx.com static void nxt_java_websocket_handler(nxt_unit_websocket_frame_t *ws); 381157Smax.romanov@nginx.com static void nxt_java_close_handler(nxt_unit_request_info_t *req); 39*1684Smax.romanov@nginx.com static int nxt_java_ready_handler(nxt_unit_ctx_t *ctx); 40*1684Smax.romanov@nginx.com static void *nxt_java_thread_func(void *main_ctx); 41*1684Smax.romanov@nginx.com static int nxt_java_init_threads(nxt_java_app_conf_t *c); 42*1684Smax.romanov@nginx.com static void nxt_java_join_threads(nxt_unit_ctx_t *ctx, 43*1684Smax.romanov@nginx.com nxt_java_app_conf_t *c); 44977Smax.romanov@gmail.com 45977Smax.romanov@gmail.com static uint32_t compat[] = { 46977Smax.romanov@gmail.com NXT_VERNUM, NXT_DEBUG, 47977Smax.romanov@gmail.com }; 48977Smax.romanov@gmail.com 49977Smax.romanov@gmail.com char *nxt_java_modules; 50977Smax.romanov@gmail.com 51*1684Smax.romanov@nginx.com static pthread_t *nxt_java_threads; 52*1684Smax.romanov@nginx.com static pthread_attr_t *nxt_java_thread_attr; 53*1684Smax.romanov@nginx.com 54977Smax.romanov@gmail.com 55977Smax.romanov@gmail.com #define NXT_STRING(x) _NXT_STRING(x) 56977Smax.romanov@gmail.com #define _NXT_STRING(x) #x 57977Smax.romanov@gmail.com 58977Smax.romanov@gmail.com NXT_EXPORT nxt_app_module_t nxt_app_module = { 59977Smax.romanov@gmail.com sizeof(compat), 60977Smax.romanov@gmail.com compat, 61977Smax.romanov@gmail.com nxt_string("java"), 62977Smax.romanov@gmail.com NXT_STRING(NXT_JAVA_VERSION), 631489St.nateldemoura@f5.com nxt_java_mounts, 641489St.nateldemoura@f5.com nxt_nitems(nxt_java_mounts), 651488St.nateldemoura@f5.com nxt_java_setup, 661488St.nateldemoura@f5.com nxt_java_start, 67977Smax.romanov@gmail.com }; 68977Smax.romanov@gmail.com 69977Smax.romanov@gmail.com typedef struct { 70*1684Smax.romanov@nginx.com JavaVM *jvm; 71*1684Smax.romanov@nginx.com jobject cl; 72*1684Smax.romanov@nginx.com jobject ctx; 73*1684Smax.romanov@nginx.com nxt_java_app_conf_t *conf; 74977Smax.romanov@gmail.com } nxt_java_data_t; 75977Smax.romanov@gmail.com 76977Smax.romanov@gmail.com 77977Smax.romanov@gmail.com static nxt_int_t 781488St.nateldemoura@f5.com nxt_java_setup(nxt_task_t *task, nxt_process_t *process, 791488St.nateldemoura@f5.com nxt_common_app_conf_t *conf) 80977Smax.romanov@gmail.com { 811489St.nateldemoura@f5.com char *path, *relpath, *p, *rootfs; 821489St.nateldemoura@f5.com size_t jars_dir_len, rootfs_len; 83977Smax.romanov@gmail.com const char *unit_jars; 84977Smax.romanov@gmail.com 851489St.nateldemoura@f5.com rootfs = (char *) process->isolation.rootfs; 861489St.nateldemoura@f5.com rootfs_len = 0; 871489St.nateldemoura@f5.com 88977Smax.romanov@gmail.com unit_jars = conf->u.java.unit_jars; 89977Smax.romanov@gmail.com if (unit_jars == NULL) { 901489St.nateldemoura@f5.com if (rootfs != NULL) { 911489St.nateldemoura@f5.com unit_jars = "/"; 921489St.nateldemoura@f5.com } else { 931489St.nateldemoura@f5.com unit_jars = NXT_JARS; 941489St.nateldemoura@f5.com } 95977Smax.romanov@gmail.com } 96977Smax.romanov@gmail.com 971489St.nateldemoura@f5.com relpath = strdup(unit_jars); 981489St.nateldemoura@f5.com if (nxt_slow_path(relpath == NULL)) { 99977Smax.romanov@gmail.com return NXT_ERROR; 100977Smax.romanov@gmail.com } 101977Smax.romanov@gmail.com 1021489St.nateldemoura@f5.com if (rootfs != NULL) { 1031489St.nateldemoura@f5.com jars_dir_len = strlen(unit_jars); 1041489St.nateldemoura@f5.com rootfs_len = strlen(rootfs); 1051489St.nateldemoura@f5.com 1061489St.nateldemoura@f5.com path = nxt_malloc(jars_dir_len + rootfs_len + 1); 1071489St.nateldemoura@f5.com if (nxt_slow_path(path == NULL)) { 1081489St.nateldemoura@f5.com free(relpath); 1091489St.nateldemoura@f5.com return NXT_ERROR; 1101489St.nateldemoura@f5.com } 1111489St.nateldemoura@f5.com 1121489St.nateldemoura@f5.com p = nxt_cpymem(path, process->isolation.rootfs, rootfs_len); 1131489St.nateldemoura@f5.com p = nxt_cpymem(p, relpath, jars_dir_len); 1141489St.nateldemoura@f5.com *p = '\0'; 1151489St.nateldemoura@f5.com 1161489St.nateldemoura@f5.com free(relpath); 1171489St.nateldemoura@f5.com 1181489St.nateldemoura@f5.com } else { 1191489St.nateldemoura@f5.com path = relpath; 1201489St.nateldemoura@f5.com } 1211489St.nateldemoura@f5.com 1221489St.nateldemoura@f5.com nxt_java_modules = realpath(path, NULL); 1231489St.nateldemoura@f5.com if (nxt_java_modules == NULL) { 1241489St.nateldemoura@f5.com nxt_alert(task, "realpath(\"%s\") failed %E", path, nxt_errno); 1251489St.nateldemoura@f5.com goto free; 1261489St.nateldemoura@f5.com } 1271489St.nateldemoura@f5.com 1281489St.nateldemoura@f5.com if (rootfs != NULL && strlen(path) > rootfs_len) { 1291489St.nateldemoura@f5.com nxt_java_modules = path + rootfs_len; 1301489St.nateldemoura@f5.com } 1311489St.nateldemoura@f5.com 1321489St.nateldemoura@f5.com nxt_debug(task, "JAVA MODULES: %s", nxt_java_modules); 1331489St.nateldemoura@f5.com 134977Smax.romanov@gmail.com return NXT_OK; 1351489St.nateldemoura@f5.com 1361489St.nateldemoura@f5.com free: 1371489St.nateldemoura@f5.com 1381489St.nateldemoura@f5.com nxt_free(path); 1391489St.nateldemoura@f5.com 1401489St.nateldemoura@f5.com return NXT_ERROR; 141977Smax.romanov@gmail.com } 142977Smax.romanov@gmail.com 143977Smax.romanov@gmail.com 144977Smax.romanov@gmail.com static char ** 145977Smax.romanov@gmail.com nxt_java_module_jars(const char *jars[], int jar_count) 146977Smax.romanov@gmail.com { 147977Smax.romanov@gmail.com char **res, *jurl; 1481489St.nateldemoura@f5.com uint8_t pathsep; 149977Smax.romanov@gmail.com nxt_int_t modules_len, jlen, i; 150977Smax.romanov@gmail.com const char **jar; 151977Smax.romanov@gmail.com 152977Smax.romanov@gmail.com res = nxt_malloc(jar_count * sizeof(char*)); 153977Smax.romanov@gmail.com if (res == NULL) { 154977Smax.romanov@gmail.com return NULL; 155977Smax.romanov@gmail.com } 156977Smax.romanov@gmail.com 157977Smax.romanov@gmail.com modules_len = nxt_strlen(nxt_java_modules); 158977Smax.romanov@gmail.com 1591489St.nateldemoura@f5.com pathsep = nxt_java_modules[modules_len - 1] == '/'; 1601489St.nateldemoura@f5.com 161977Smax.romanov@gmail.com for (i = 0, jar = jars; *jar != NULL; jar++) { 1621489St.nateldemoura@f5.com jlen = nxt_length("file:") + modules_len 1631489St.nateldemoura@f5.com + (!pathsep ? nxt_length("/") : 0) 1641489St.nateldemoura@f5.com + nxt_strlen(*jar) + 1; 1651489St.nateldemoura@f5.com 166977Smax.romanov@gmail.com jurl = nxt_malloc(jlen); 167977Smax.romanov@gmail.com if (jurl == NULL) { 168977Smax.romanov@gmail.com return NULL; 169977Smax.romanov@gmail.com } 170977Smax.romanov@gmail.com 171977Smax.romanov@gmail.com res[i++] = jurl; 172977Smax.romanov@gmail.com 173977Smax.romanov@gmail.com jurl = nxt_cpymem(jurl, "file:", nxt_length("file:")); 174977Smax.romanov@gmail.com jurl = nxt_cpymem(jurl, nxt_java_modules, modules_len); 1751489St.nateldemoura@f5.com 1761489St.nateldemoura@f5.com if (!pathsep) { 1771489St.nateldemoura@f5.com *jurl++ = '/'; 1781489St.nateldemoura@f5.com } 1791489St.nateldemoura@f5.com 180977Smax.romanov@gmail.com jurl = nxt_cpymem(jurl, *jar, nxt_strlen(*jar)); 181977Smax.romanov@gmail.com *jurl++ = '\0'; 182977Smax.romanov@gmail.com } 183977Smax.romanov@gmail.com 184977Smax.romanov@gmail.com return res; 185977Smax.romanov@gmail.com } 186977Smax.romanov@gmail.com 187977Smax.romanov@gmail.com 188977Smax.romanov@gmail.com static nxt_int_t 1891488St.nateldemoura@f5.com nxt_java_start(nxt_task_t *task, nxt_process_data_t *data) 190977Smax.romanov@gmail.com { 1911488St.nateldemoura@f5.com jint rc; 1921488St.nateldemoura@f5.com char *opt, *real_path; 1931488St.nateldemoura@f5.com char **classpath_arr, **unit_jars, **system_jars; 1941488St.nateldemoura@f5.com JavaVM *jvm; 1951488St.nateldemoura@f5.com JNIEnv *env; 1961488St.nateldemoura@f5.com jobject cl, classpath; 1971488St.nateldemoura@f5.com nxt_str_t str; 1981488St.nateldemoura@f5.com nxt_int_t opt_len, real_path_len; 1991488St.nateldemoura@f5.com nxt_uint_t i, unit_jars_count, classpath_count; 2001488St.nateldemoura@f5.com nxt_uint_t system_jars_count; 2011488St.nateldemoura@f5.com JavaVMOption *jvm_opt; 2021488St.nateldemoura@f5.com JavaVMInitArgs jvm_args; 2031488St.nateldemoura@f5.com nxt_unit_ctx_t *ctx; 2041488St.nateldemoura@f5.com nxt_unit_init_t java_init; 2051488St.nateldemoura@f5.com nxt_java_data_t java_data; 2061488St.nateldemoura@f5.com nxt_conf_value_t *value; 2071488St.nateldemoura@f5.com nxt_java_app_conf_t *c; 2081488St.nateldemoura@f5.com nxt_common_app_conf_t *app_conf; 209977Smax.romanov@gmail.com 210977Smax.romanov@gmail.com //setenv("ASAN_OPTIONS", "handle_segv=0", 1); 211977Smax.romanov@gmail.com 212977Smax.romanov@gmail.com jvm_args.version = JNI_VERSION_1_6; 213977Smax.romanov@gmail.com jvm_args.nOptions = 0; 214977Smax.romanov@gmail.com jvm_args.ignoreUnrecognized = 0; 215977Smax.romanov@gmail.com 2161488St.nateldemoura@f5.com app_conf = data->app; 2171488St.nateldemoura@f5.com c = &app_conf->u.java; 218977Smax.romanov@gmail.com 219977Smax.romanov@gmail.com if (c->options != NULL) { 220977Smax.romanov@gmail.com jvm_args.nOptions += nxt_conf_array_elements_count(c->options); 221977Smax.romanov@gmail.com } 222977Smax.romanov@gmail.com 223977Smax.romanov@gmail.com jvm_opt = nxt_malloc(jvm_args.nOptions * sizeof(JavaVMOption)); 224977Smax.romanov@gmail.com if (jvm_opt == NULL) { 225977Smax.romanov@gmail.com nxt_alert(task, "failed to allocate jvm_opt"); 226977Smax.romanov@gmail.com return NXT_ERROR; 227977Smax.romanov@gmail.com } 228977Smax.romanov@gmail.com 229977Smax.romanov@gmail.com jvm_args.options = jvm_opt; 230977Smax.romanov@gmail.com 231977Smax.romanov@gmail.com unit_jars_count = nxt_nitems(nxt_java_unit_jars) - 1; 232977Smax.romanov@gmail.com 233977Smax.romanov@gmail.com unit_jars = nxt_java_module_jars(nxt_java_unit_jars, unit_jars_count); 234977Smax.romanov@gmail.com if (unit_jars == NULL) { 235977Smax.romanov@gmail.com nxt_alert(task, "failed to allocate buffer for unit_jars array"); 236977Smax.romanov@gmail.com 237977Smax.romanov@gmail.com return NXT_ERROR; 238977Smax.romanov@gmail.com } 239977Smax.romanov@gmail.com 240977Smax.romanov@gmail.com system_jars_count = nxt_nitems(nxt_java_system_jars) - 1; 241977Smax.romanov@gmail.com 242977Smax.romanov@gmail.com system_jars = nxt_java_module_jars(nxt_java_system_jars, system_jars_count); 243977Smax.romanov@gmail.com if (system_jars == NULL) { 244977Smax.romanov@gmail.com nxt_alert(task, "failed to allocate buffer for system_jars array"); 245977Smax.romanov@gmail.com 246977Smax.romanov@gmail.com return NXT_ERROR; 247977Smax.romanov@gmail.com } 248977Smax.romanov@gmail.com 249977Smax.romanov@gmail.com if (c->options != NULL) { 250977Smax.romanov@gmail.com 251977Smax.romanov@gmail.com for (i = 0; /* void */ ; i++) { 252977Smax.romanov@gmail.com value = nxt_conf_get_array_element(c->options, i); 253977Smax.romanov@gmail.com if (value == NULL) { 254977Smax.romanov@gmail.com break; 255977Smax.romanov@gmail.com } 256977Smax.romanov@gmail.com 257977Smax.romanov@gmail.com nxt_conf_get_string(value, &str); 258977Smax.romanov@gmail.com 259977Smax.romanov@gmail.com opt = nxt_malloc(str.length + 1); 260977Smax.romanov@gmail.com if (opt == NULL) { 261977Smax.romanov@gmail.com nxt_alert(task, "failed to allocate jvm_opt"); 262977Smax.romanov@gmail.com return NXT_ERROR; 263977Smax.romanov@gmail.com } 264977Smax.romanov@gmail.com 265977Smax.romanov@gmail.com memcpy(opt, str.start, str.length); 266977Smax.romanov@gmail.com opt[str.length] = '\0'; 267977Smax.romanov@gmail.com 268977Smax.romanov@gmail.com jvm_opt[i].optionString = opt; 269977Smax.romanov@gmail.com } 270977Smax.romanov@gmail.com } 271977Smax.romanov@gmail.com 272977Smax.romanov@gmail.com if (c->classpath != NULL) { 273977Smax.romanov@gmail.com classpath_count = nxt_conf_array_elements_count(c->classpath); 274977Smax.romanov@gmail.com classpath_arr = nxt_malloc(classpath_count * sizeof(char *)); 275977Smax.romanov@gmail.com 276977Smax.romanov@gmail.com for (i = 0; /* void */ ; i++) { 277977Smax.romanov@gmail.com value = nxt_conf_get_array_element(c->classpath, i); 278977Smax.romanov@gmail.com if (value == NULL) { 279977Smax.romanov@gmail.com break; 280977Smax.romanov@gmail.com } 281977Smax.romanov@gmail.com 282977Smax.romanov@gmail.com nxt_conf_get_string(value, &str); 283977Smax.romanov@gmail.com 284977Smax.romanov@gmail.com opt_len = str.length + 1; 285977Smax.romanov@gmail.com 286977Smax.romanov@gmail.com char *sc = memchr(str.start, ':', str.length); 287977Smax.romanov@gmail.com if (sc == NULL && str.start[0] == '/') { 288977Smax.romanov@gmail.com opt_len += nxt_length("file:"); 289977Smax.romanov@gmail.com } 290977Smax.romanov@gmail.com 291977Smax.romanov@gmail.com opt = nxt_malloc(opt_len); 292977Smax.romanov@gmail.com if (opt == NULL) { 293977Smax.romanov@gmail.com nxt_alert(task, "failed to allocate classpath"); 294977Smax.romanov@gmail.com return NXT_ERROR; 295977Smax.romanov@gmail.com } 296977Smax.romanov@gmail.com 297977Smax.romanov@gmail.com if (sc == NULL && str.start[0] != '/') { 298977Smax.romanov@gmail.com nxt_memcpy(opt, str.start, str.length); 299977Smax.romanov@gmail.com opt[str.length] = '\0'; 300977Smax.romanov@gmail.com 301977Smax.romanov@gmail.com real_path = realpath(opt, NULL); 302977Smax.romanov@gmail.com if (real_path == NULL) { 303977Smax.romanov@gmail.com nxt_alert(task, "realpath(%s) failed: %E", opt, nxt_errno); 304977Smax.romanov@gmail.com return NXT_ERROR; 305977Smax.romanov@gmail.com } 306977Smax.romanov@gmail.com 307977Smax.romanov@gmail.com real_path_len = nxt_strlen(real_path); 308977Smax.romanov@gmail.com 309977Smax.romanov@gmail.com free(opt); 310977Smax.romanov@gmail.com 311977Smax.romanov@gmail.com opt_len = nxt_length("file:") + real_path_len + 1; 312977Smax.romanov@gmail.com 313977Smax.romanov@gmail.com opt = nxt_malloc(opt_len); 314977Smax.romanov@gmail.com if (opt == NULL) { 315977Smax.romanov@gmail.com nxt_alert(task, "failed to allocate classpath"); 316977Smax.romanov@gmail.com return NXT_ERROR; 317977Smax.romanov@gmail.com } 318977Smax.romanov@gmail.com 319977Smax.romanov@gmail.com } else { 320977Smax.romanov@gmail.com real_path = (char *) str.start; /* I love this cast! */ 321977Smax.romanov@gmail.com real_path_len = str.length; 322977Smax.romanov@gmail.com } 323977Smax.romanov@gmail.com 324977Smax.romanov@gmail.com classpath_arr[i] = opt; 325977Smax.romanov@gmail.com 326977Smax.romanov@gmail.com if (sc == NULL) { 327977Smax.romanov@gmail.com opt = nxt_cpymem(opt, "file:", nxt_length("file:")); 328977Smax.romanov@gmail.com } 329977Smax.romanov@gmail.com 330977Smax.romanov@gmail.com opt = nxt_cpymem(opt, real_path, real_path_len); 331977Smax.romanov@gmail.com *opt = '\0'; 332977Smax.romanov@gmail.com } 333977Smax.romanov@gmail.com 334977Smax.romanov@gmail.com } else { 335977Smax.romanov@gmail.com classpath_count = 0; 336977Smax.romanov@gmail.com classpath_arr = NULL; 337977Smax.romanov@gmail.com } 338977Smax.romanov@gmail.com 339977Smax.romanov@gmail.com rc = JNI_CreateJavaVM(&jvm, (void **) &env, &jvm_args); 340977Smax.romanov@gmail.com if (rc != JNI_OK) { 341977Smax.romanov@gmail.com nxt_alert(task, "failed to create Java VM: %d", (int) rc); 342977Smax.romanov@gmail.com return NXT_ERROR; 343977Smax.romanov@gmail.com } 344977Smax.romanov@gmail.com 345977Smax.romanov@gmail.com rc = nxt_java_initThread(env); 346977Smax.romanov@gmail.com if (rc != NXT_UNIT_OK) { 347977Smax.romanov@gmail.com nxt_alert(task, "nxt_java_initThread() failed"); 348977Smax.romanov@gmail.com goto env_failed; 349977Smax.romanov@gmail.com } 350977Smax.romanov@gmail.com 351977Smax.romanov@gmail.com rc = nxt_java_initURLClassLoader(env); 352977Smax.romanov@gmail.com if (rc != NXT_UNIT_OK) { 353977Smax.romanov@gmail.com nxt_alert(task, "nxt_java_initURLClassLoader() failed"); 354977Smax.romanov@gmail.com goto env_failed; 355977Smax.romanov@gmail.com } 356977Smax.romanov@gmail.com 357977Smax.romanov@gmail.com cl = nxt_java_newURLClassLoader(env, system_jars_count, system_jars); 358977Smax.romanov@gmail.com if (cl == NULL) { 359977Smax.romanov@gmail.com nxt_alert(task, "nxt_java_newURLClassLoader failed"); 360977Smax.romanov@gmail.com goto env_failed; 361977Smax.romanov@gmail.com } 362977Smax.romanov@gmail.com 363977Smax.romanov@gmail.com nxt_java_setContextClassLoader(env, cl); 364977Smax.romanov@gmail.com 365977Smax.romanov@gmail.com cl = nxt_java_newURLClassLoader_parent(env, unit_jars_count, unit_jars, cl); 366977Smax.romanov@gmail.com if (cl == NULL) { 367977Smax.romanov@gmail.com nxt_alert(task, "nxt_java_newURLClassLoader_parent failed"); 368977Smax.romanov@gmail.com goto env_failed; 369977Smax.romanov@gmail.com } 370977Smax.romanov@gmail.com 371977Smax.romanov@gmail.com nxt_java_setContextClassLoader(env, cl); 372977Smax.romanov@gmail.com 373977Smax.romanov@gmail.com rc = nxt_java_initContext(env, cl); 374977Smax.romanov@gmail.com if (rc != NXT_UNIT_OK) { 375977Smax.romanov@gmail.com nxt_alert(task, "nxt_java_initContext() failed"); 376977Smax.romanov@gmail.com goto env_failed; 377977Smax.romanov@gmail.com } 378977Smax.romanov@gmail.com 379977Smax.romanov@gmail.com rc = nxt_java_initRequest(env, cl); 380977Smax.romanov@gmail.com if (rc != NXT_UNIT_OK) { 381977Smax.romanov@gmail.com nxt_alert(task, "nxt_java_initRequest() failed"); 382977Smax.romanov@gmail.com goto env_failed; 383977Smax.romanov@gmail.com } 384977Smax.romanov@gmail.com 385977Smax.romanov@gmail.com rc = nxt_java_initResponse(env, cl); 386977Smax.romanov@gmail.com if (rc != NXT_UNIT_OK) { 387977Smax.romanov@gmail.com nxt_alert(task, "nxt_java_initResponse() failed"); 388977Smax.romanov@gmail.com goto env_failed; 389977Smax.romanov@gmail.com } 390977Smax.romanov@gmail.com 391977Smax.romanov@gmail.com rc = nxt_java_initInputStream(env, cl); 392977Smax.romanov@gmail.com if (rc != NXT_UNIT_OK) { 393977Smax.romanov@gmail.com nxt_alert(task, "nxt_java_initInputStream() failed"); 394977Smax.romanov@gmail.com goto env_failed; 395977Smax.romanov@gmail.com } 396977Smax.romanov@gmail.com 397977Smax.romanov@gmail.com rc = nxt_java_initOutputStream(env, cl); 398977Smax.romanov@gmail.com if (rc != NXT_UNIT_OK) { 399977Smax.romanov@gmail.com nxt_alert(task, "nxt_java_initOutputStream() failed"); 400977Smax.romanov@gmail.com goto env_failed; 401977Smax.romanov@gmail.com } 402977Smax.romanov@gmail.com 403977Smax.romanov@gmail.com nxt_java_jni_init(env); 404977Smax.romanov@gmail.com if (rc != NXT_UNIT_OK) { 405977Smax.romanov@gmail.com nxt_alert(task, "nxt_java_jni_init() failed"); 406977Smax.romanov@gmail.com goto env_failed; 407977Smax.romanov@gmail.com } 408977Smax.romanov@gmail.com 409977Smax.romanov@gmail.com classpath = nxt_java_newURLs(env, classpath_count, classpath_arr); 410977Smax.romanov@gmail.com if (classpath == NULL) { 411977Smax.romanov@gmail.com nxt_alert(task, "nxt_java_newURLs failed"); 412977Smax.romanov@gmail.com goto env_failed; 413977Smax.romanov@gmail.com } 414977Smax.romanov@gmail.com 415*1684Smax.romanov@nginx.com java_data.jvm = jvm; 416*1684Smax.romanov@nginx.com java_data.cl = cl; 4171488St.nateldemoura@f5.com java_data.ctx = nxt_java_startContext(env, c->webapp, classpath); 418*1684Smax.romanov@nginx.com java_data.conf = c; 419977Smax.romanov@gmail.com 420977Smax.romanov@gmail.com if ((*env)->ExceptionCheck(env)) { 421977Smax.romanov@gmail.com nxt_alert(task, "Unhandled exception in application start"); 422977Smax.romanov@gmail.com (*env)->ExceptionDescribe(env); 423977Smax.romanov@gmail.com return NXT_ERROR; 424977Smax.romanov@gmail.com } 425977Smax.romanov@gmail.com 426*1684Smax.romanov@nginx.com rc = nxt_java_init_threads(c); 427*1684Smax.romanov@nginx.com if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { 428*1684Smax.romanov@nginx.com return NXT_ERROR; 429*1684Smax.romanov@nginx.com } 430*1684Smax.romanov@nginx.com 431977Smax.romanov@gmail.com nxt_unit_default_init(task, &java_init); 432977Smax.romanov@gmail.com 433977Smax.romanov@gmail.com java_init.callbacks.request_handler = nxt_java_request_handler; 4341157Smax.romanov@nginx.com java_init.callbacks.websocket_handler = nxt_java_websocket_handler; 4351157Smax.romanov@nginx.com java_init.callbacks.close_handler = nxt_java_close_handler; 436*1684Smax.romanov@nginx.com java_init.callbacks.ready_handler = nxt_java_ready_handler; 437977Smax.romanov@gmail.com java_init.request_data_size = sizeof(nxt_java_request_data_t); 4381488St.nateldemoura@f5.com java_init.data = &java_data; 439*1684Smax.romanov@nginx.com java_init.ctx_data = env; 4401488St.nateldemoura@f5.com java_init.shm_limit = app_conf->shm_limit; 441977Smax.romanov@gmail.com 442977Smax.romanov@gmail.com ctx = nxt_unit_init(&java_init); 443977Smax.romanov@gmail.com if (nxt_slow_path(ctx == NULL)) { 444977Smax.romanov@gmail.com nxt_alert(task, "nxt_unit_init() failed"); 445977Smax.romanov@gmail.com return NXT_ERROR; 446977Smax.romanov@gmail.com } 447977Smax.romanov@gmail.com 448977Smax.romanov@gmail.com rc = nxt_unit_run(ctx); 449*1684Smax.romanov@nginx.com 450*1684Smax.romanov@nginx.com nxt_java_join_threads(ctx, c); 451977Smax.romanov@gmail.com 4521488St.nateldemoura@f5.com nxt_java_stopContext(env, java_data.ctx); 453977Smax.romanov@gmail.com 454977Smax.romanov@gmail.com if ((*env)->ExceptionCheck(env)) { 455977Smax.romanov@gmail.com (*env)->ExceptionDescribe(env); 456977Smax.romanov@gmail.com } 457977Smax.romanov@gmail.com 4581157Smax.romanov@nginx.com nxt_unit_done(ctx); 4591157Smax.romanov@nginx.com 460977Smax.romanov@gmail.com (*jvm)->DestroyJavaVM(jvm); 461977Smax.romanov@gmail.com 462*1684Smax.romanov@nginx.com exit(rc); 463977Smax.romanov@gmail.com 464977Smax.romanov@gmail.com return NXT_OK; 465977Smax.romanov@gmail.com 466977Smax.romanov@gmail.com env_failed: 467977Smax.romanov@gmail.com 468977Smax.romanov@gmail.com if ((*env)->ExceptionCheck(env)) { 469977Smax.romanov@gmail.com (*env)->ExceptionDescribe(env); 470977Smax.romanov@gmail.com } 471977Smax.romanov@gmail.com 472977Smax.romanov@gmail.com return NXT_ERROR; 473977Smax.romanov@gmail.com } 474977Smax.romanov@gmail.com 475977Smax.romanov@gmail.com 476977Smax.romanov@gmail.com static void 477977Smax.romanov@gmail.com nxt_java_request_handler(nxt_unit_request_info_t *req) 478977Smax.romanov@gmail.com { 479977Smax.romanov@gmail.com JNIEnv *env; 480977Smax.romanov@gmail.com jobject jreq, jresp; 481977Smax.romanov@gmail.com nxt_java_data_t *java_data; 482977Smax.romanov@gmail.com nxt_java_request_data_t *data; 483977Smax.romanov@gmail.com 484977Smax.romanov@gmail.com java_data = req->unit->data; 485*1684Smax.romanov@nginx.com env = req->ctx->data; 486977Smax.romanov@gmail.com data = req->data; 487977Smax.romanov@gmail.com 488977Smax.romanov@gmail.com jreq = nxt_java_newRequest(env, java_data->ctx, req); 489977Smax.romanov@gmail.com if (jreq == NULL) { 490977Smax.romanov@gmail.com nxt_unit_req_alert(req, "failed to create Request instance"); 491977Smax.romanov@gmail.com 492977Smax.romanov@gmail.com if ((*env)->ExceptionCheck(env)) { 493977Smax.romanov@gmail.com (*env)->ExceptionDescribe(env); 494977Smax.romanov@gmail.com (*env)->ExceptionClear(env); 495977Smax.romanov@gmail.com } 496977Smax.romanov@gmail.com 497977Smax.romanov@gmail.com nxt_unit_request_done(req, NXT_UNIT_ERROR); 498977Smax.romanov@gmail.com return; 499977Smax.romanov@gmail.com } 500977Smax.romanov@gmail.com 501977Smax.romanov@gmail.com jresp = nxt_java_newResponse(env, req); 502977Smax.romanov@gmail.com if (jresp == NULL) { 503977Smax.romanov@gmail.com nxt_unit_req_alert(req, "failed to create Response instance"); 504977Smax.romanov@gmail.com 505977Smax.romanov@gmail.com if ((*env)->ExceptionCheck(env)) { 506977Smax.romanov@gmail.com (*env)->ExceptionDescribe(env); 507977Smax.romanov@gmail.com (*env)->ExceptionClear(env); 508977Smax.romanov@gmail.com } 509977Smax.romanov@gmail.com 510977Smax.romanov@gmail.com (*env)->DeleteLocalRef(env, jreq); 511977Smax.romanov@gmail.com 512977Smax.romanov@gmail.com nxt_unit_request_done(req, NXT_UNIT_ERROR); 513977Smax.romanov@gmail.com return; 514977Smax.romanov@gmail.com } 515977Smax.romanov@gmail.com 516977Smax.romanov@gmail.com data->header_size = 10 * 1024; 517977Smax.romanov@gmail.com data->buf_size = 32 * 1024; /* from Jetty */ 518977Smax.romanov@gmail.com data->jreq = jreq; 519977Smax.romanov@gmail.com data->jresp = jresp; 520977Smax.romanov@gmail.com data->buf = NULL; 521977Smax.romanov@gmail.com 522977Smax.romanov@gmail.com nxt_unit_request_group_dup_fields(req); 523977Smax.romanov@gmail.com 524977Smax.romanov@gmail.com nxt_java_service(env, java_data->ctx, jreq, jresp); 525977Smax.romanov@gmail.com 526977Smax.romanov@gmail.com if ((*env)->ExceptionCheck(env)) { 527977Smax.romanov@gmail.com (*env)->ExceptionDescribe(env); 528977Smax.romanov@gmail.com (*env)->ExceptionClear(env); 529977Smax.romanov@gmail.com } 530977Smax.romanov@gmail.com 531977Smax.romanov@gmail.com if (!nxt_unit_response_is_init(req)) { 532977Smax.romanov@gmail.com nxt_unit_response_init(req, 200, 0, 0); 533977Smax.romanov@gmail.com } 534977Smax.romanov@gmail.com 535977Smax.romanov@gmail.com if (!nxt_unit_response_is_sent(req)) { 536977Smax.romanov@gmail.com nxt_unit_response_send(req); 537977Smax.romanov@gmail.com } 538977Smax.romanov@gmail.com 539977Smax.romanov@gmail.com if (data->buf != NULL) { 540977Smax.romanov@gmail.com nxt_unit_buf_send(data->buf); 541977Smax.romanov@gmail.com 542977Smax.romanov@gmail.com data->buf = NULL; 543977Smax.romanov@gmail.com } 544977Smax.romanov@gmail.com 5451157Smax.romanov@nginx.com if (nxt_unit_response_is_websocket(req)) { 5461157Smax.romanov@nginx.com data->jreq = (*env)->NewGlobalRef(env, jreq); 5471157Smax.romanov@nginx.com data->jresp = (*env)->NewGlobalRef(env, jresp); 5481157Smax.romanov@nginx.com 5491157Smax.romanov@nginx.com } else { 5501157Smax.romanov@nginx.com nxt_unit_request_done(req, NXT_UNIT_OK); 5511157Smax.romanov@nginx.com } 5521157Smax.romanov@nginx.com 553977Smax.romanov@gmail.com (*env)->DeleteLocalRef(env, jresp); 554977Smax.romanov@gmail.com (*env)->DeleteLocalRef(env, jreq); 5551157Smax.romanov@nginx.com } 5561157Smax.romanov@nginx.com 5571157Smax.romanov@nginx.com 5581157Smax.romanov@nginx.com static void 5591157Smax.romanov@nginx.com nxt_java_websocket_handler(nxt_unit_websocket_frame_t *ws) 5601157Smax.romanov@nginx.com { 5611157Smax.romanov@nginx.com void *b; 5621157Smax.romanov@nginx.com JNIEnv *env; 5631157Smax.romanov@nginx.com jobject jbuf; 5641157Smax.romanov@nginx.com nxt_java_request_data_t *data; 5651157Smax.romanov@nginx.com 566*1684Smax.romanov@nginx.com env = ws->req->ctx->data; 5671157Smax.romanov@nginx.com data = ws->req->data; 5681157Smax.romanov@nginx.com 5691157Smax.romanov@nginx.com b = malloc(ws->payload_len); 5701157Smax.romanov@nginx.com if (b != NULL) { 5711157Smax.romanov@nginx.com nxt_unit_websocket_read(ws, b, ws->payload_len); 5721157Smax.romanov@nginx.com 5731157Smax.romanov@nginx.com jbuf = (*env)->NewDirectByteBuffer(env, b, ws->payload_len); 5741157Smax.romanov@nginx.com if (jbuf != NULL) { 5751157Smax.romanov@nginx.com nxt_java_Request_websocket(env, data->jreq, jbuf, 5761157Smax.romanov@nginx.com ws->header->opcode, ws->header->fin); 5771157Smax.romanov@nginx.com 5781157Smax.romanov@nginx.com if ((*env)->ExceptionCheck(env)) { 5791157Smax.romanov@nginx.com (*env)->ExceptionDescribe(env); 5801157Smax.romanov@nginx.com (*env)->ExceptionClear(env); 5811157Smax.romanov@nginx.com } 5821157Smax.romanov@nginx.com 5831157Smax.romanov@nginx.com (*env)->DeleteLocalRef(env, jbuf); 5841157Smax.romanov@nginx.com } 5851157Smax.romanov@nginx.com 5861157Smax.romanov@nginx.com free(b); 5871157Smax.romanov@nginx.com } 5881157Smax.romanov@nginx.com 5891157Smax.romanov@nginx.com nxt_unit_websocket_done(ws); 5901157Smax.romanov@nginx.com } 5911157Smax.romanov@nginx.com 5921157Smax.romanov@nginx.com 5931157Smax.romanov@nginx.com static void 5941157Smax.romanov@nginx.com nxt_java_close_handler(nxt_unit_request_info_t *req) 5951157Smax.romanov@nginx.com { 5961157Smax.romanov@nginx.com JNIEnv *env; 5971157Smax.romanov@nginx.com nxt_java_request_data_t *data; 5981157Smax.romanov@nginx.com 599*1684Smax.romanov@nginx.com env = req->ctx->data; 6001157Smax.romanov@nginx.com data = req->data; 6011157Smax.romanov@nginx.com 6021157Smax.romanov@nginx.com nxt_java_Request_close(env, data->jreq); 6031157Smax.romanov@nginx.com 6041157Smax.romanov@nginx.com (*env)->DeleteGlobalRef(env, data->jresp); 6051157Smax.romanov@nginx.com (*env)->DeleteGlobalRef(env, data->jreq); 606977Smax.romanov@gmail.com 607977Smax.romanov@gmail.com nxt_unit_request_done(req, NXT_UNIT_OK); 608977Smax.romanov@gmail.com } 609977Smax.romanov@gmail.com 610*1684Smax.romanov@nginx.com 611*1684Smax.romanov@nginx.com static int 612*1684Smax.romanov@nginx.com nxt_java_ready_handler(nxt_unit_ctx_t *ctx) 613*1684Smax.romanov@nginx.com { 614*1684Smax.romanov@nginx.com int res; 615*1684Smax.romanov@nginx.com uint32_t i; 616*1684Smax.romanov@nginx.com nxt_java_data_t *java_data; 617*1684Smax.romanov@nginx.com nxt_java_app_conf_t *c; 618*1684Smax.romanov@nginx.com 619*1684Smax.romanov@nginx.com /* Worker thread context. */ 620*1684Smax.romanov@nginx.com if (!nxt_unit_is_main_ctx(ctx)) { 621*1684Smax.romanov@nginx.com return NXT_UNIT_OK; 622*1684Smax.romanov@nginx.com } 623*1684Smax.romanov@nginx.com 624*1684Smax.romanov@nginx.com java_data = ctx->unit->data; 625*1684Smax.romanov@nginx.com c = java_data->conf; 626*1684Smax.romanov@nginx.com 627*1684Smax.romanov@nginx.com if (c->threads <= 1) { 628*1684Smax.romanov@nginx.com return NXT_UNIT_OK; 629*1684Smax.romanov@nginx.com } 630*1684Smax.romanov@nginx.com 631*1684Smax.romanov@nginx.com for (i = 0; i < c->threads - 1; i++) { 632*1684Smax.romanov@nginx.com res = pthread_create(&nxt_java_threads[i], nxt_java_thread_attr, 633*1684Smax.romanov@nginx.com nxt_java_thread_func, ctx); 634*1684Smax.romanov@nginx.com 635*1684Smax.romanov@nginx.com if (nxt_fast_path(res == 0)) { 636*1684Smax.romanov@nginx.com nxt_unit_debug(ctx, "thread #%d created", (int) (i + 1)); 637*1684Smax.romanov@nginx.com 638*1684Smax.romanov@nginx.com } else { 639*1684Smax.romanov@nginx.com nxt_unit_alert(ctx, "thread #%d create failed: %s (%d)", 640*1684Smax.romanov@nginx.com (int) (i + 1), strerror(res), res); 641*1684Smax.romanov@nginx.com 642*1684Smax.romanov@nginx.com return NXT_UNIT_ERROR; 643*1684Smax.romanov@nginx.com } 644*1684Smax.romanov@nginx.com } 645*1684Smax.romanov@nginx.com 646*1684Smax.romanov@nginx.com return NXT_UNIT_OK; 647*1684Smax.romanov@nginx.com } 648*1684Smax.romanov@nginx.com 649*1684Smax.romanov@nginx.com 650*1684Smax.romanov@nginx.com static void * 651*1684Smax.romanov@nginx.com nxt_java_thread_func(void *data) 652*1684Smax.romanov@nginx.com { 653*1684Smax.romanov@nginx.com int rc; 654*1684Smax.romanov@nginx.com JavaVM *jvm; 655*1684Smax.romanov@nginx.com JNIEnv *env; 656*1684Smax.romanov@nginx.com nxt_unit_ctx_t *main_ctx, *ctx; 657*1684Smax.romanov@nginx.com nxt_java_data_t *java_data; 658*1684Smax.romanov@nginx.com 659*1684Smax.romanov@nginx.com main_ctx = data; 660*1684Smax.romanov@nginx.com 661*1684Smax.romanov@nginx.com nxt_unit_debug(main_ctx, "worker thread start"); 662*1684Smax.romanov@nginx.com 663*1684Smax.romanov@nginx.com java_data = main_ctx->unit->data; 664*1684Smax.romanov@nginx.com jvm = java_data->jvm; 665*1684Smax.romanov@nginx.com 666*1684Smax.romanov@nginx.com rc = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL); 667*1684Smax.romanov@nginx.com if (rc != JNI_OK) { 668*1684Smax.romanov@nginx.com nxt_unit_alert(main_ctx, "failed to attach Java VM: %d", (int) rc); 669*1684Smax.romanov@nginx.com return NULL; 670*1684Smax.romanov@nginx.com } 671*1684Smax.romanov@nginx.com 672*1684Smax.romanov@nginx.com nxt_java_setContextClassLoader(env, java_data->cl); 673*1684Smax.romanov@nginx.com 674*1684Smax.romanov@nginx.com ctx = nxt_unit_ctx_alloc(main_ctx, env); 675*1684Smax.romanov@nginx.com if (nxt_slow_path(ctx == NULL)) { 676*1684Smax.romanov@nginx.com goto fail; 677*1684Smax.romanov@nginx.com } 678*1684Smax.romanov@nginx.com 679*1684Smax.romanov@nginx.com (void) nxt_unit_run(ctx); 680*1684Smax.romanov@nginx.com 681*1684Smax.romanov@nginx.com nxt_unit_done(ctx); 682*1684Smax.romanov@nginx.com 683*1684Smax.romanov@nginx.com fail: 684*1684Smax.romanov@nginx.com 685*1684Smax.romanov@nginx.com (*jvm)->DetachCurrentThread(jvm); 686*1684Smax.romanov@nginx.com 687*1684Smax.romanov@nginx.com nxt_unit_debug(NULL, "worker thread end"); 688*1684Smax.romanov@nginx.com 689*1684Smax.romanov@nginx.com return NULL; 690*1684Smax.romanov@nginx.com } 691*1684Smax.romanov@nginx.com 692*1684Smax.romanov@nginx.com 693*1684Smax.romanov@nginx.com static int 694*1684Smax.romanov@nginx.com nxt_java_init_threads(nxt_java_app_conf_t *c) 695*1684Smax.romanov@nginx.com { 696*1684Smax.romanov@nginx.com int res; 697*1684Smax.romanov@nginx.com static pthread_attr_t attr; 698*1684Smax.romanov@nginx.com 699*1684Smax.romanov@nginx.com if (c->threads <= 1) { 700*1684Smax.romanov@nginx.com return NXT_UNIT_OK; 701*1684Smax.romanov@nginx.com } 702*1684Smax.romanov@nginx.com 703*1684Smax.romanov@nginx.com if (c->thread_stack_size > 0) { 704*1684Smax.romanov@nginx.com res = pthread_attr_init(&attr); 705*1684Smax.romanov@nginx.com if (nxt_slow_path(res != 0)) { 706*1684Smax.romanov@nginx.com nxt_unit_alert(NULL, "thread attr init failed: %s (%d)", 707*1684Smax.romanov@nginx.com strerror(res), res); 708*1684Smax.romanov@nginx.com 709*1684Smax.romanov@nginx.com return NXT_UNIT_ERROR; 710*1684Smax.romanov@nginx.com } 711*1684Smax.romanov@nginx.com 712*1684Smax.romanov@nginx.com res = pthread_attr_setstacksize(&attr, c->thread_stack_size); 713*1684Smax.romanov@nginx.com if (nxt_slow_path(res != 0)) { 714*1684Smax.romanov@nginx.com nxt_unit_alert(NULL, "thread attr set stack size failed: %s (%d)", 715*1684Smax.romanov@nginx.com strerror(res), res); 716*1684Smax.romanov@nginx.com 717*1684Smax.romanov@nginx.com return NXT_UNIT_ERROR; 718*1684Smax.romanov@nginx.com } 719*1684Smax.romanov@nginx.com 720*1684Smax.romanov@nginx.com nxt_java_thread_attr = &attr; 721*1684Smax.romanov@nginx.com } 722*1684Smax.romanov@nginx.com 723*1684Smax.romanov@nginx.com nxt_java_threads = nxt_unit_malloc(NULL, 724*1684Smax.romanov@nginx.com sizeof(pthread_t) * (c->threads - 1)); 725*1684Smax.romanov@nginx.com if (nxt_slow_path(nxt_java_threads == NULL)) { 726*1684Smax.romanov@nginx.com nxt_unit_alert(NULL, "Failed to allocate thread id array"); 727*1684Smax.romanov@nginx.com 728*1684Smax.romanov@nginx.com return NXT_UNIT_ERROR; 729*1684Smax.romanov@nginx.com } 730*1684Smax.romanov@nginx.com 731*1684Smax.romanov@nginx.com memset(nxt_java_threads, 0, sizeof(pthread_t) * (c->threads - 1)); 732*1684Smax.romanov@nginx.com 733*1684Smax.romanov@nginx.com return NXT_UNIT_OK; 734*1684Smax.romanov@nginx.com } 735*1684Smax.romanov@nginx.com 736*1684Smax.romanov@nginx.com 737*1684Smax.romanov@nginx.com static void 738*1684Smax.romanov@nginx.com nxt_java_join_threads(nxt_unit_ctx_t *ctx, nxt_java_app_conf_t *c) 739*1684Smax.romanov@nginx.com { 740*1684Smax.romanov@nginx.com int res; 741*1684Smax.romanov@nginx.com uint32_t i; 742*1684Smax.romanov@nginx.com 743*1684Smax.romanov@nginx.com if (nxt_java_threads == NULL) { 744*1684Smax.romanov@nginx.com return; 745*1684Smax.romanov@nginx.com } 746*1684Smax.romanov@nginx.com 747*1684Smax.romanov@nginx.com for (i = 0; i < c->threads - 1; i++) { 748*1684Smax.romanov@nginx.com if ((uintptr_t) nxt_java_threads[i] == 0) { 749*1684Smax.romanov@nginx.com continue; 750*1684Smax.romanov@nginx.com } 751*1684Smax.romanov@nginx.com 752*1684Smax.romanov@nginx.com res = pthread_join(nxt_java_threads[i], NULL); 753*1684Smax.romanov@nginx.com 754*1684Smax.romanov@nginx.com if (nxt_fast_path(res == 0)) { 755*1684Smax.romanov@nginx.com nxt_unit_debug(ctx, "thread #%d joined", (int) i); 756*1684Smax.romanov@nginx.com 757*1684Smax.romanov@nginx.com } else { 758*1684Smax.romanov@nginx.com nxt_unit_alert(ctx, "thread #%d join failed: %s (%d)", 759*1684Smax.romanov@nginx.com (int) i, strerror(res), res); 760*1684Smax.romanov@nginx.com } 761*1684Smax.romanov@nginx.com } 762*1684Smax.romanov@nginx.com 763*1684Smax.romanov@nginx.com nxt_unit_free(ctx, nxt_java_threads); 764*1684Smax.romanov@nginx.com } 765*1684Smax.romanov@nginx.com 766*1684Smax.romanov@nginx.com 767