annotate src/se/native/com/oracle/dio/dio_common.cpp @ 257:67353093ce02

DIO-23: [I2C] UnavailableDeviceException when Zulu JRE is used > Reviewed-by: duke
author snazarki
date Thu, 02 Feb 2017 15:09:24 +0300
parents 5c8f58479d59
children ff88da88dd88
rev   line source
duke@0 1 /*
duke@0 2 * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
duke@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@0 4 *
duke@0 5 * This code is free software; you can redistribute it and/or modify it
duke@0 6 * under the terms of the GNU General Public License version 2 only, as
duke@0 7 * published by the Free Software Foundation. Oracle designates this
duke@0 8 * particular file as subject to the "Classpath" exception as provided
duke@0 9 * by Oracle in the LICENSE file that accompanied this code.
duke@0 10 *
duke@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@0 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@0 15 * accompanied this code).
duke@0 16 *
duke@0 17 * You should have received a copy of the GNU General Public License version
duke@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@0 20 *
duke@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
duke@0 22 * or visit www.oracle.com if you need additional information or have any
duke@0 23 * questions.
duke@0 24 */
duke@0 25
duke@0 26 #include <dio_common.h>
duke@0 27 #include <javacall_os.h>
jld@1 28 #include <javacall_logging.h>
jld@1 29 #include <javacall_memory.h>
duke@0 30 #include <javautil_linked_list.h>
duke@0 31
duke@0 32 /* Java VM interface */
duke@0 33 static JavaVM* globalJavaVM = NULL;
duke@0 34
duke@0 35 /* Internal structure of a device reference */
duke@0 36 struct _device_reference {
duke@0 37 javacall_handle handle;
duke@0 38 javacall_int32 refcount;
duke@0 39 javacall_mutex mutex;
duke@0 40 device_closer closer;
duke@0 41 device_locker locker;
duke@0 42 device_unlocker unlocker;
duke@0 43 };
duke@0 44
duke@0 45 /* Signal descriptor */
duke@0 46 struct signal {
duke@0 47 signal_type type;
duke@0 48 javacall_handle target;
duke@0 49 javacall_handle parameter;
duke@0 50 javacall_cond condition;
duke@0 51 };
duke@0 52
duke@0 53 /* Signal descriptor list */
duke@0 54 static javacall_handle signals = NULL;
duke@0 55
duke@0 56 /* Signal descriptor list mutex */
duke@0 57 static javacall_mutex signalMutex = NULL;
duke@0 58
jld@10 59 /* Device reference list */
jld@10 60 static javacall_handle devlist = NULL;
jld@10 61
jld@10 62 /* Device reference list mutex */
jld@10 63 static javacall_mutex devlistMutex = NULL;
jld@10 64
duke@0 65 /* Cleanup */
duke@0 66 static void dioCleanup() {
duke@0 67 if (NULL != signalMutex) {
duke@0 68 javacall_os_mutex_destroy(signalMutex);
duke@0 69 signalMutex = NULL;
duke@0 70 }
duke@0 71 if (NULL != signals) {
duke@0 72 javautil_list_destroy(signals);
duke@0 73 signals = NULL;
duke@0 74 }
jld@10 75 if (NULL != devlistMutex) {
jld@10 76 javacall_os_mutex_destroy(devlistMutex);
jld@10 77 devlistMutex = NULL;
jld@10 78 }
jld@10 79 if (NULL != devlist) {
jld@10 80 javautil_list_destroy(devlist);
jld@10 81 devlist = NULL;
jld@10 82 }
duke@0 83 }
duke@0 84
duke@0 85 /* Returns a global reference to VM */
duke@0 86 JavaVM* getGlobalJavaVM() {
duke@0 87 return globalJavaVM;
duke@0 88 }
duke@0 89
duke@0 90 /* Creates a reference to the device identified by handle */
duke@0 91 device_reference createDeviceReference(javacall_handle handle, device_closer closer,
duke@0 92 device_locker locker, device_unlocker unlocker) {
duke@0 93 device_reference device;
duke@0 94 if ((device = (device_reference)javacall_calloc(1, sizeof(_device_reference))) == NULL) {
duke@0 95 return INVALID_DEVICE_REFERENCE;
duke@0 96 }
duke@0 97 if ((device->mutex = javacall_os_mutex_create()) == NULL) {
duke@0 98 javacall_free(device);
duke@0 99 return INVALID_DEVICE_REFERENCE;
duke@0 100 }
duke@0 101 device->handle = handle;
duke@0 102 device->refcount = 1;
duke@0 103 device->closer = closer;
duke@0 104 device->locker = locker;
duke@0 105 device->unlocker = unlocker;
jld@10 106 javacall_os_mutex_lock(devlistMutex);
jld@10 107 javautil_list_add(devlist, device);
jld@10 108 javacall_os_mutex_unlock(devlistMutex);
duke@0 109 return device;
duke@0 110 }
duke@0 111
duke@0 112 static jobject getHandleObjectFromDeviceObject(JNIEnv* env, jobject deviceObj) {
duke@0 113 // to improve performance the references below should be cached
duke@0 114 jclass deviceBaseClass = env->FindClass("com/oracle/dio/impl/AbstractPeripheral");
duke@0 115 if (deviceBaseClass == NULL) {
duke@0 116 return NULL;
duke@0 117 }
duke@0 118 jfieldID deviceHandleField = env->GetFieldID(deviceBaseClass, "handle", "Lcom/oracle/dio/impl/Handle;");
duke@0 119 if (deviceHandleField == NULL) {
duke@0 120 return NULL;
duke@0 121 }
duke@0 122 return env->GetObjectField(deviceObj, deviceHandleField);
duke@0 123 }
duke@0 124
jld@4 125 static javacall_dio_result saveDeviceReferenceToHandleObject(JNIEnv* env,
jld@4 126 jobject handleObj,
jld@4 127 device_reference device) {
duke@0 128 // to improve performance the references below should be cached
duke@0 129 jclass deviceHandleClass = env->FindClass("com/oracle/dio/impl/Handle");
duke@0 130 if (deviceHandleClass == NULL) {
jld@4 131 return JAVACALL_DIO_FAIL;
duke@0 132 }
duke@0 133 jfieldID deviceNativeHandleField = env->GetFieldID(deviceHandleClass, "device_reference", "I");
duke@0 134 if (deviceNativeHandleField == NULL) {
jld@4 135 return JAVACALL_DIO_FAIL;
duke@0 136 }
duke@0 137 env->SetIntField(handleObj, deviceNativeHandleField, (jint)device);
jld@4 138 return JAVACALL_DIO_OK;
duke@0 139 }
duke@0 140
duke@0 141 static device_reference getDeviceReferenceFromHandleObject(JNIEnv* env,
duke@0 142 jobject handleObj) {
duke@0 143 // to improve performance the references below should be cached
duke@0 144 jclass deviceHandleClass = env->FindClass("com/oracle/dio/impl/Handle");
duke@0 145 if (deviceHandleClass == NULL) {
duke@0 146 return INVALID_DEVICE_REFERENCE;
duke@0 147 }
duke@0 148 jfieldID deviceNativeHandleField = env->GetFieldID(deviceHandleClass, "device_reference", "I");
duke@0 149 if (deviceNativeHandleField == NULL) {
duke@0 150 return INVALID_DEVICE_REFERENCE;
duke@0 151 }
duke@0 152 jint value = env->GetIntField(handleObj, deviceNativeHandleField);
duke@0 153 return (device_reference)value;
duke@0 154 }
duke@0 155
duke@0 156 /* Saves the reference to an instance of AbstractPeripheral */
jld@4 157 javacall_dio_result saveDeviceReferenceToDeviceObject(JNIEnv* env, jobject deviceObj,
jld@4 158 device_reference device) {
duke@0 159 jobject handleObj = getHandleObjectFromDeviceObject(env, deviceObj);
duke@0 160 if (handleObj == NULL) {
jld@4 161 return JAVACALL_DIO_FAIL;
duke@0 162 }
duke@0 163 return saveDeviceReferenceToHandleObject(env, handleObj, device);
duke@0 164 }
duke@0 165
duke@0 166 /* Returns a reference stored by an instance of AbstractPeripheral */
duke@0 167 device_reference getDeviceReferenceFromDeviceObject(JNIEnv* env, jobject deviceObj) {
duke@0 168 jobject handleObj = getHandleObjectFromDeviceObject(env, deviceObj);
duke@0 169 if (handleObj == NULL) {
duke@0 170 return INVALID_DEVICE_REFERENCE;
duke@0 171 }
duke@0 172 return getDeviceReferenceFromHandleObject(env, handleObj);
duke@0 173 }
duke@0 174
duke@0 175 /* Returns the handle associated with the device reference */
duke@0 176 javacall_handle getDeviceHandle(device_reference device) {
duke@0 177 return device->handle;
duke@0 178 }
duke@0 179
duke@0 180 /* Restricted use only.
duke@0 181 * Retains the device reference by incrementing its reference counter, thus
duke@0 182 * preventing it from being immediately destroyed by releaseDeviceReference().
duke@0 183 * Must be balanced with a call to releaseDeviceReference() to let the
duke@0 184 * reference be finally destroyed. */
duke@0 185 void retainDeviceReference(device_reference device) {
duke@0 186 javacall_os_mutex_lock(device->mutex);
duke@0 187 device->refcount++;
duke@0 188 javacall_os_mutex_unlock(device->mutex);
duke@0 189 }
duke@0 190
duke@0 191 /* Releases a reference */
duke@0 192 void releaseDeviceReference(device_reference device) {
jld@22 193 if (device == NULL) {
jld@22 194 return;
jld@22 195 }
duke@0 196 javacall_mutex m = device->mutex;
duke@0 197 javacall_os_mutex_lock(m);
duke@0 198 if (--device->refcount == 0) {
jld@10 199 javacall_os_mutex_lock(devlistMutex);
jld@10 200 javautil_list_remove(devlist, device);
duke@0 201 javacall_free(device);
jld@10 202 javacall_os_mutex_unlock(devlistMutex);
duke@0 203 device = NULL;
duke@0 204 }
duke@0 205 javacall_os_mutex_unlock(m);
duke@0 206 if (device == NULL) {
duke@0 207 javacall_os_mutex_destroy(m);
duke@0 208 }
duke@0 209 }
duke@0 210
jld@49 211 /* Returns an existing reference to the device identified by handle. */
jld@10 212 device_reference getDeviceReference(javacall_handle handle) {
jld@10 213 device_reference device = INVALID_DEVICE_REFERENCE;
jld@10 214 javacall_os_mutex_lock(devlistMutex);
jld@10 215 javautil_list_reset_iterator(devlist);
jld@10 216 device_reference d = NULL;
jld@10 217 while (javautil_list_get_next(devlist, (void**)&d) == JAVACALL_OK) {
jld@10 218 if (d->handle == handle) {
jld@10 219 device = d;
jld@10 220 break;
jld@10 221 }
jld@10 222 }
jld@10 223 javacall_os_mutex_unlock(devlistMutex);
jld@10 224 return device;
jld@10 225 }
jld@10 226
duke@0 227 static void destroySignal(signal* sig) {
duke@0 228 if (sig->condition != NULL) {
duke@0 229 javacall_mutex m = javacall_os_cond_get_mutex(sig->condition);
duke@0 230 if (m != NULL) {
duke@0 231 javacall_os_mutex_destroy(m);
duke@0 232 }
duke@0 233 javacall_os_cond_destroy(sig->condition);
duke@0 234 }
duke@0 235 javacall_free(sig);
duke@0 236 }
duke@0 237
duke@0 238 static signal* createSignal(signal_type signalType, javacall_handle signalTarget) {
duke@0 239 signal* sig;
duke@0 240 if ((sig = (signal*)javacall_calloc(1, sizeof(signal))) == NULL) {
duke@0 241 return NULL;
duke@0 242 }
duke@0 243
duke@0 244 javacall_mutex cond_mutex;
duke@0 245 if ((cond_mutex = javacall_os_mutex_create()) == NULL) {
duke@0 246 destroySignal(sig);
duke@0 247 return NULL;
duke@0 248 }
duke@0 249 if ((sig->condition = javacall_os_cond_create(cond_mutex)) == NULL) {
duke@0 250 javacall_os_mutex_destroy(cond_mutex);
duke@0 251 destroySignal(sig);
duke@0 252 return NULL;
duke@0 253 }
duke@0 254
duke@0 255 sig->type = signalType;
duke@0 256 sig->target = signalTarget;
duke@0 257 return sig;
duke@0 258 }
duke@0 259
duke@0 260 static signal* findTarget(signal_type signalType, javacall_handle signalTarget) {
duke@0 261 signal* sig = NULL;
jld@10 262 javautil_list_reset_iterator(signals);
duke@0 263 while (javautil_list_get_next(signals, (void**)&sig) == JAVACALL_OK) {
duke@0 264 if (sig->type == signalType && sig->target == signalTarget) {
jld@10 265 return sig;
duke@0 266 }
duke@0 267 }
jld@10 268 return NULL;
jld@10 269 }
duke@0 270
duke@0 271 /* Blocks the current thread, until a signal is received, or the timeout expires */
jld@4 272 javacall_dio_result waitForSignal(signal_type signalType, javacall_handle signalTarget,
jld@4 273 /*OUT*/ javacall_handle* signalParameter, long timeout) {
duke@0 274 signal* sig = NULL;
duke@0 275
duke@0 276 javacall_os_mutex_lock(signalMutex);
jld@49 277 if ((sig = findTarget(signalType, signalTarget)) == NULL) {
duke@0 278 sig = createSignal(signalType, signalTarget);
duke@0 279 if (sig != NULL) {
duke@0 280 javautil_list_add(signals, sig);
jld@49 281
jld@49 282 javacall_os_mutex_unlock(signalMutex);
jld@49 283 javacall_os_cond_wait(sig->condition, timeout);
duke@0 284 }
jld@49 285 } else {
jld@49 286 javacall_os_mutex_unlock(signalMutex);
duke@0 287 }
duke@0 288
jld@49 289 javacall_dio_result result = JAVACALL_DIO_OUT_OF_MEMORY;
jld@49 290
jld@49 291 if (sig) {
jld@49 292 result = JAVACALL_DIO_OK;
duke@0 293
duke@0 294 javacall_os_mutex_lock(signalMutex);
duke@0 295 javautil_list_remove(signals, sig);
duke@0 296 javacall_os_mutex_unlock(signalMutex);
duke@0 297
duke@0 298 if (signalParameter != NULL) {
duke@0 299 *signalParameter = sig->parameter;
duke@0 300 }
duke@0 301
duke@0 302 destroySignal(sig);
duke@0 303 }
duke@0 304
duke@0 305 return result;
duke@0 306 }
duke@0 307
duke@0 308 /* Unblocks a thread that is waiting for a signal */
duke@0 309 void generateSignal(signal_type signalType, javacall_handle signalTarget,
duke@0 310 javacall_handle signalParameter) {
duke@0 311 javacall_os_mutex_lock(signalMutex);
duke@0 312
duke@0 313 signal* sig = findTarget(signalType, signalTarget);
duke@0 314 if (sig != NULL) {
duke@0 315 sig->parameter = signalParameter;
duke@0 316 javacall_os_cond_signal(sig->condition);
jld@49 317 } else {
jld@49 318 // signal is being sent before wait started
jld@49 319 // create the signal and add it to the list
jld@49 320 sig = createSignal(signalType, signalTarget);
jld@49 321 if (sig != NULL) {
jld@49 322 sig->parameter = signalParameter;
jld@49 323 javautil_list_add(signals, sig);
jld@49 324 }
duke@0 325 }
duke@0 326
duke@0 327 javacall_os_mutex_unlock(signalMutex);
duke@0 328 }
duke@0 329
duke@0 330 /* Closes the referenced device */
jld@4 331 javacall_dio_result closeDevice(device_reference device) {
jld@22 332 if (device == NULL) {
jld@22 333 return JAVACALL_DIO_INVALID_ARGUMENT;
jld@22 334 }
duke@0 335 if (device->closer == NULL) {
jld@4 336 return JAVACALL_DIO_FAIL;
duke@0 337 }
duke@0 338 if (device->handle != JAVACALL_INVALID_HANDLE) {
duke@0 339 device->closer(device->handle);
duke@0 340 device->handle = JAVACALL_INVALID_HANDLE;
duke@0 341 }
jld@4 342 return JAVACALL_DIO_OK;
duke@0 343 }
duke@0 344
duke@0 345 /* Locks the referenced device */
jld@4 346 javacall_dio_result lockDevice(device_reference device, /*OUT*/ javacall_handle* owner) {
duke@0 347 if (device->locker == NULL || device->handle == JAVACALL_INVALID_HANDLE) {
jld@4 348 return JAVACALL_DIO_FAIL;
duke@0 349 }
duke@0 350 return device->locker(device->handle, owner);
duke@0 351 }
duke@0 352
duke@0 353 /* Unlocks the referenced device */
jld@4 354 javacall_dio_result unlockDevice(device_reference device) {
duke@0 355 if (device->unlocker == NULL || device->handle == JAVACALL_INVALID_HANDLE) {
jld@4 356 return JAVACALL_DIO_FAIL;
duke@0 357 }
duke@0 358 return device->unlocker(device->handle);
duke@0 359 }
duke@0 360
duke@0 361
duke@0 362 extern "C" {
duke@0 363
snazarki@81 364 static int global_severity = 1; // WARNINGS, ERRORS, CRITICALS
snazarki@81 365
duke@0 366 /* Native logging initialization */
duke@0 367 void javacall_logging_initialize(void) {
duke@0 368 // Stubbed, unless this feature is required
duke@0 369 }
duke@0 370
jld@1 371 void javacall_logging_printf(int severity, javacall_logging_channel channelID,
jld@1 372 const char* filename, int lineno, const char *format, ...)
jld@1 373 {
snazarki@81 374 if (severity >= global_severity) {
snazarki@81 375 va_list args;
snazarki@81 376 va_start(args, format);
snazarki@81 377 printf("From: %s, line %d\n", filename, lineno);
snazarki@81 378 vprintf(format, args);
snazarki@81 379 printf("\n");
snazarki@81 380 va_end(args);
snazarki@81 381 }
jld@1 382 }
jld@1 383
duke@0 384 /*******************************************************************************
duke@0 385 * JNI functions
duke@0 386 */
duke@0 387
duke@0 388 /* The VM calls this function upon loading the native library. */
duke@0 389 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* jvm, void* reserved) {
duke@0 390
duke@0 391 globalJavaVM = jvm;
duke@0 392 javacall_os_initialize();
duke@0 393
duke@0 394 if (javautil_list_create(&signals) != JAVACALL_OK) {
duke@0 395 dioCleanup();
duke@0 396 return JNI_ERR;
duke@0 397 }
duke@0 398
duke@0 399 if ((signalMutex = javacall_os_mutex_create()) == NULL) {
duke@0 400 dioCleanup();
duke@0 401 return JNI_ERR;
duke@0 402 }
jld@10 403 if (javautil_list_create(&devlist) != JAVACALL_OK) {
jld@10 404 dioCleanup();
jld@10 405 return JNI_ERR;
jld@10 406 }
jld@10 407 if ((devlistMutex = javacall_os_mutex_create()) == NULL) {
jld@10 408 dioCleanup();
jld@10 409 return JNI_ERR;
jld@10 410 }
duke@0 411
duke@0 412 return JNI_VERSION_1_2;
duke@0 413 }
duke@0 414
duke@0 415 /* This function is called when the native library gets unloaded by the VM. */
duke@0 416 JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* jvm, void* reserved) {
duke@0 417 dioCleanup();
duke@0 418 javacall_os_dispose();
duke@0 419 globalJavaVM = NULL;
duke@0 420 }
duke@0 421
duke@0 422 /*
duke@0 423 * Closes the device.
duke@0 424 * Class: com_oracle_dio_impl_Handle
duke@0 425 * Method: close
duke@0 426 */
duke@0 427 JNIEXPORT void JNICALL Java_com_oracle_dio_impl_Handle_close
duke@0 428 (JNIEnv* env, jobject obj) {
duke@0 429 device_reference device = getDeviceReferenceFromHandleObject(env, obj);
duke@0 430 if (device != INVALID_DEVICE_REFERENCE) {
duke@0 431 saveDeviceReferenceToHandleObject(env, obj, INVALID_DEVICE_REFERENCE);
duke@0 432 closeDevice(device);
duke@0 433 releaseDeviceReference(device);
duke@0 434 }
duke@0 435 }
duke@0 436
duke@0 437 /*
duke@0 438 * Tries locking the device.
duke@0 439 * Class: com_oracle_dio_impl_Handle
duke@0 440 * Method: tryLock
duke@0 441 */
snazarki@257 442 JNIEXPORT bool JNICALL Java_com_oracle_dio_impl_Handle_tryLock
duke@0 443 (JNIEnv* env, jobject obj, jint timeout) {
duke@0 444 device_reference device = getDeviceReferenceFromHandleObject(env, obj);
duke@0 445 if (device != INVALID_DEVICE_REFERENCE) {
duke@0 446 // add an implementation
duke@0 447 }
snazarki@257 448
snazarki@257 449 return true;
duke@0 450 }
duke@0 451
duke@0 452 /*
duke@0 453 * Unlocks the device.
duke@0 454 * Class: com_oracle_dio_impl_Handle
duke@0 455 * Method: unlock
duke@0 456 */
duke@0 457 JNIEXPORT void JNICALL Java_com_oracle_dio_impl_Handle_unlock
duke@0 458 (JNIEnv* env, jobject obj) {
duke@0 459 device_reference device = getDeviceReferenceFromHandleObject(env, obj);
duke@0 460 if (device != INVALID_DEVICE_REFERENCE) {
duke@0 461 // add an implementation
duke@0 462 }
duke@0 463 }
duke@0 464
duke@0 465 } // extern "C" /* JNI functions */