comparison android/dw.cpp @ 2801:b004cc75d574

Android: Remove the _DW_EVENT_THREADING experiment. While it was more simple to launch a new thread to handle each event, this approach had numerous drawbacks. No reasonable way to limit the number of threads or memory consumed. Order of operations problems, the thread scheduler would control the order in which the events were handled, not the order of events produced by the UI. The non-threaded version has been working and stable for a while now even though it is more complicated for us to maintain our own event queue... this allows us to make sure the events are handled in order and we can limit the number of events in tight system resource situations.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Sun, 17 Jul 2022 21:03:31 +0000
parents 0c534743b7a9
children f910da0418f6
comparison
equal deleted inserted replaced
2800:56eab3a84b62 2801:b004cc75d574
34 34
35 #ifdef __cplusplus 35 #ifdef __cplusplus
36 extern "C" { 36 extern "C" {
37 #endif 37 #endif
38 38
39 /* Define this to enable threading for events...
40 * most Android events don't handle return values, so
41 * we can launch a new thread to handle the event.
42 * #define _DW_EVENT_THREADING
43 */
44 /* #define _DW_EVENT_THREADING */
45 #define DW_CLASS_NAME "org/dbsoft/dwindows/DWindows" 39 #define DW_CLASS_NAME "org/dbsoft/dwindows/DWindows"
46 40
47 /* Dynamic Windows internal variables */ 41 /* Dynamic Windows internal variables */
48 static char _dw_app_id[_DW_APP_ID_SIZE+1]= {0}; 42 static char _dw_app_id[_DW_APP_ID_SIZE+1]= {0};
49 static char _dw_app_name[_DW_APP_ID_SIZE+1]= {0}; 43 static char _dw_app_name[_DW_APP_ID_SIZE+1]= {0};
457 retval = htmlchangedfunc(handler->window, DW_POINTER_TO_INT(params[3]), uri, handler->data); 451 retval = htmlchangedfunc(handler->window, DW_POINTER_TO_INT(params[3]), uri, handler->data);
458 break; 452 break;
459 } 453 }
460 } 454 }
461 } 455 }
462 #ifdef _DW_EVENT_THREADING
463 /* Free the memory we allocated for this tread */
464 if(params[1])
465 free(params[1]);
466 if(params[2])
467 free(params[2]);
468 free(params);
469 #endif
470 return retval; 456 return retval;
471 } 457 }
472 458
473 /* If we aren't using threading, we create a queue of events... 459 /* We create a queue of events... the oldest event indexed by
474 * the oldest event indexed by _dw_event_head, the newest by 460 * _dw_event_head, the newest by _dw_event_tail.
475 * _dw_event_tail. 461 */
476 */
477 #ifndef _DW_EVENT_THREADING
478 #define _DW_EVENT_QUEUE_LENGTH 10 462 #define _DW_EVENT_QUEUE_LENGTH 10
479 void *_dw_event_queue[_DW_EVENT_QUEUE_LENGTH][_DW_EVENT_PARAM_SIZE]; 463 void *_dw_event_queue[_DW_EVENT_QUEUE_LENGTH][_DW_EVENT_PARAM_SIZE];
480 int _dw_event_head = -1, _dw_event_tail = -1, _dw_main_active = TRUE; 464 int _dw_event_head = -1, _dw_event_tail = -1, _dw_main_active = TRUE;
481 HMTX _dw_event_mutex = nullptr; 465 HMTX _dw_event_mutex = nullptr;
482 DWTID _dw_main_thread = -1; 466 DWTID _dw_main_thread = -1;
557 dw_event_post(_dw_main_event); 541 dw_event_post(_dw_main_event);
558 } 542 }
559 dw_mutex_unlock(_dw_event_mutex); 543 dw_mutex_unlock(_dw_event_mutex);
560 return retval; 544 return retval;
561 } 545 }
562 #endif
563 546
564 int _dw_event_handler(jobject object, void **params) 547 int _dw_event_handler(jobject object, void **params)
565 { 548 {
566 int messageid = DW_POINTER_TO_INT(params[8]); 549 int messageid = DW_POINTER_TO_INT(params[8]);
567 DWSignalHandler *handler = _dw_get_handler(object, messageid); 550 DWSignalHandler *handler = _dw_get_handler(object, messageid);
574 * If it isn't a draw event, either queue the event 557 * If it isn't a draw event, either queue the event
575 * or launch a new thread to handle it. 558 * or launch a new thread to handle it.
576 */ 559 */
577 if(DW_POINTER_TO_INT(params[8]) != _DW_EVENT_EXPOSE) 560 if(DW_POINTER_TO_INT(params[8]) != _DW_EVENT_EXPOSE)
578 { 561 {
579 #ifdef _DW_EVENT_THREADING
580 /* Make a copy of the params so it isn't allocated from the stack */
581 void *newparams = calloc(_DW_EVENT_PARAM_SIZE, sizeof(void *));
582
583 memcpy(newparams, params, _DW_EVENT_PARAM_SIZE * sizeof(void *));
584 dw_thread_new((void *) _dw_event_handler2, newparams, 0);
585 #else
586 /* Push the new event onto the queue if it fits */ 562 /* Push the new event onto the queue if it fits */
587 _dw_queue_event(params); 563 _dw_queue_event(params);
588 #endif
589 } 564 }
590 else 565 else
591 return _dw_event_handler2(params); 566 return _dw_event_handler2(params);
592 567
593 } /* If we don't have a handler, destroy the window */ 568 } /* If we don't have a handler, destroy the window */
601 */ 576 */
602 JNIEXPORT jint JNICALL 577 JNIEXPORT jint JNICALL
603 Java_org_dbsoft_dwindows_DWindows_eventHandler(JNIEnv* env, jobject obj, jobject obj1, jobject obj2, 578 Java_org_dbsoft_dwindows_DWindows_eventHandler(JNIEnv* env, jobject obj, jobject obj1, jobject obj2,
604 jint message, jstring str1, jstring str2, 579 jint message, jstring str1, jstring str2,
605 jint inta, jint intb, jint intc, jint intd) { 580 jint inta, jint intb, jint intc, jint intd) {
606 #ifdef _DW_EVENT_THREADING
607 char *utf81 = str1 ? strdup(env->GetStringUTFChars(str1, nullptr)) : nullptr;
608 char *utf82 = str2 ? strdup(env->GetStringUTFChars(str2, nullptr)) : nullptr;
609 #else
610 const char *utf81 = str1 ? env->GetStringUTFChars(str1, nullptr) : nullptr; 581 const char *utf81 = str1 ? env->GetStringUTFChars(str1, nullptr) : nullptr;
611 const char *utf82 = str2 ? env->GetStringUTFChars(str2, nullptr) : nullptr; 582 const char *utf82 = str2 ? env->GetStringUTFChars(str2, nullptr) : nullptr;
612 #endif
613 void *params[_DW_EVENT_PARAM_SIZE] = { DW_POINTER(obj2), DW_POINTER(utf81), DW_POINTER(utf82), 583 void *params[_DW_EVENT_PARAM_SIZE] = { DW_POINTER(obj2), DW_POINTER(utf81), DW_POINTER(utf82),
614 DW_INT_TO_POINTER(inta), DW_INT_TO_POINTER(intb), 584 DW_INT_TO_POINTER(inta), DW_INT_TO_POINTER(intb),
615 DW_INT_TO_POINTER(intc), DW_INT_TO_POINTER(intd), nullptr, 585 DW_INT_TO_POINTER(intc), DW_INT_TO_POINTER(intd), nullptr,
616 DW_INT_TO_POINTER(message), nullptr }; 586 DW_INT_TO_POINTER(message), nullptr };
617 587
641 611
642 /* Handlers for HTML events */ 612 /* Handlers for HTML events */
643 JNIEXPORT void JNICALL 613 JNIEXPORT void JNICALL
644 Java_org_dbsoft_dwindows_DWindows_eventHandlerHTMLResult(JNIEnv* env, jobject obj, jobject obj1, 614 Java_org_dbsoft_dwindows_DWindows_eventHandlerHTMLResult(JNIEnv* env, jobject obj, jobject obj1,
645 jint message, jstring htmlResult, jlong data) { 615 jint message, jstring htmlResult, jlong data) {
646 #ifdef _DW_EVENT_THREADING
647 char *result = strdup(env->GetStringUTFChars(htmlResult, nullptr));
648 #else
649 const char *result = env->GetStringUTFChars(htmlResult, nullptr); 616 const char *result = env->GetStringUTFChars(htmlResult, nullptr);
650 #endif
651 void *params[_DW_EVENT_PARAM_SIZE] = { nullptr, DW_POINTER(result), nullptr, nullptr, nullptr, nullptr, nullptr, 617 void *params[_DW_EVENT_PARAM_SIZE] = { nullptr, DW_POINTER(result), nullptr, nullptr, nullptr, nullptr, nullptr,
652 DW_INT_TO_POINTER(data), DW_INT_TO_POINTER(message), nullptr }; 618 DW_INT_TO_POINTER(data), DW_INT_TO_POINTER(message), nullptr };
653 619
654 _dw_event_handler(obj1, params); 620 _dw_event_handler(obj1, params);
655 } 621 }
656 622
657 JNIEXPORT void JNICALL 623 JNIEXPORT void JNICALL
658 Java_org_dbsoft_dwindows_DWWebViewClient_eventHandlerHTMLChanged(JNIEnv* env, jobject obj, jobject obj1, 624 Java_org_dbsoft_dwindows_DWWebViewClient_eventHandlerHTMLChanged(JNIEnv* env, jobject obj, jobject obj1,
659 jint message, jstring URI, jint status) { 625 jint message, jstring URI, jint status) {
660 #ifdef _DW_EVENT_THREADING
661 char *uri = strdup(env->GetStringUTFChars(URI, nullptr));
662 #else
663 const char *uri = env->GetStringUTFChars(URI, nullptr); 626 const char *uri = env->GetStringUTFChars(URI, nullptr);
664 #endif
665 void *params[_DW_EVENT_PARAM_SIZE] = { nullptr, DW_POINTER(uri), nullptr, DW_INT_TO_POINTER(status), 627 void *params[_DW_EVENT_PARAM_SIZE] = { nullptr, DW_POINTER(uri), nullptr, DW_INT_TO_POINTER(status),
666 nullptr, nullptr, nullptr, nullptr, DW_INT_TO_POINTER(message), nullptr }; 628 nullptr, nullptr, nullptr, nullptr, DW_INT_TO_POINTER(message), nullptr };
667 629
668 _dw_event_handler(obj1, params); 630 _dw_event_handler(obj1, params);
669 } 631 }
767 } 729 }
768 730
769 JNIEXPORT void JNICALL 731 JNIEXPORT void JNICALL
770 Java_org_dbsoft_dwindows_DWindows_eventHandlerContainer(JNIEnv* env, jobject obj, jobject obj1, 732 Java_org_dbsoft_dwindows_DWindows_eventHandlerContainer(JNIEnv* env, jobject obj, jobject obj1,
771 jint message, jstring jtitle, jint x, jint y, jlong data) { 733 jint message, jstring jtitle, jint x, jint y, jlong data) {
772 #ifdef _DW_EVENT_THREADING
773 char *title = jtitle ? strdup(env->GetStringUTFChars(jtitle, nullptr)) : nullptr;
774 #else
775 const char *title = jtitle ? env->GetStringUTFChars(jtitle, nullptr) : nullptr; 734 const char *title = jtitle ? env->GetStringUTFChars(jtitle, nullptr) : nullptr;
776 #endif
777 void *params[_DW_EVENT_PARAM_SIZE] = { nullptr, DW_POINTER(title), nullptr, DW_INT_TO_POINTER(x), DW_INT_TO_POINTER(y), 735 void *params[_DW_EVENT_PARAM_SIZE] = { nullptr, DW_POINTER(title), nullptr, DW_INT_TO_POINTER(x), DW_INT_TO_POINTER(y),
778 nullptr, nullptr, DW_POINTER(data), DW_INT_TO_POINTER(message), nullptr }; 736 nullptr, nullptr, DW_POINTER(data), DW_INT_TO_POINTER(message), nullptr };
779 737
780 _dw_event_handler(obj1, params); 738 _dw_event_handler(obj1, params);
781 } 739 }
782 740
783 JNIEXPORT void JNICALL 741 JNIEXPORT void JNICALL
784 Java_org_dbsoft_dwindows_DWindows_eventHandlerTree(JNIEnv* env, jobject obj, jobject obj1, 742 Java_org_dbsoft_dwindows_DWindows_eventHandlerTree(JNIEnv* env, jobject obj, jobject obj1,
785 jint message, jobject item, jstring jtitle, jlong data) { 743 jint message, jobject item, jstring jtitle, jlong data) {
786 #ifdef _DW_EVENT_THREADING
787 char *title = jtitle ? strdup(env->GetStringUTFChars(jtitle, nullptr)) : nullptr;
788 #else
789 const char *title = jtitle ? env->GetStringUTFChars(jtitle, nullptr) : nullptr; 744 const char *title = jtitle ? env->GetStringUTFChars(jtitle, nullptr) : nullptr;
790 #endif
791 void *params[_DW_EVENT_PARAM_SIZE] = { DW_POINTER(item), DW_POINTER(title), nullptr, nullptr, nullptr, 745 void *params[_DW_EVENT_PARAM_SIZE] = { DW_POINTER(item), DW_POINTER(title), nullptr, nullptr, nullptr,
792 nullptr, nullptr, DW_POINTER(data), DW_INT_TO_POINTER(message), nullptr }; 746 nullptr, nullptr, DW_POINTER(data), DW_INT_TO_POINTER(message), nullptr };
793 747
794 _dw_event_handler(obj1, params); 748 _dw_event_handler(obj1, params);
795 } 749 }
804 } 758 }
805 759
806 JNIEXPORT void JNICALL 760 JNIEXPORT void JNICALL
807 Java_org_dbsoft_dwindows_DWindows_eventHandlerKey(JNIEnv *env, jobject obj, jobject obj1, jint message, jint ch, 761 Java_org_dbsoft_dwindows_DWindows_eventHandlerKey(JNIEnv *env, jobject obj, jobject obj1, jint message, jint ch,
808 jint vk, jint modifiers, jstring str) { 762 jint vk, jint modifiers, jstring str) {
809 #ifdef _DW_EVENT_THREADING
810 char *cstr = str ? strdup(env->GetStringUTFChars(str, nullptr)) : nullptr;
811 #else
812 const char *cstr = str ? env->GetStringUTFChars(str, nullptr) : nullptr; 763 const char *cstr = str ? env->GetStringUTFChars(str, nullptr) : nullptr;
813 #endif
814 void *params[_DW_EVENT_PARAM_SIZE] = { nullptr, DW_POINTER(cstr), nullptr, DW_INT_TO_POINTER(ch), DW_INT_TO_POINTER(vk), 764 void *params[_DW_EVENT_PARAM_SIZE] = { nullptr, DW_POINTER(cstr), nullptr, DW_INT_TO_POINTER(ch), DW_INT_TO_POINTER(vk),
815 DW_INT_TO_POINTER(modifiers), nullptr, nullptr, DW_INT_TO_POINTER(message), nullptr }; 765 DW_INT_TO_POINTER(modifiers), nullptr, nullptr, DW_INT_TO_POINTER(message), nullptr };
816 766
817 _dw_event_handler(obj1, params); 767 _dw_event_handler(obj1, params);
818 } 768 }
964 // Call the method on the object 914 // Call the method on the object
965 env->CallVoidMethod(_dw_obj, dwMain); 915 env->CallVoidMethod(_dw_obj, dwMain);
966 _dw_jni_check_exception(env); 916 _dw_jni_check_exception(env);
967 } 917 }
968 918
969 #ifdef _DW_EVENT_THREADING
970 /* We don't actually run a loop here,
971 * we launched a new thread to run the loop there.
972 * Just wait for dw_main_quit() on the DWMainEvent.
973 */
974 dw_event_wait(_dw_main_event, DW_TIMEOUT_INFINITE);
975 #else
976
977 /* Save our thread ID, so we know if we should handle 919 /* Save our thread ID, so we know if we should handle
978 * events in callback dw_main_sleep/iteration() calls. 920 * events in callback dw_main_sleep/iteration() calls.
979 */ 921 */
980 _dw_main_thread = dw_thread_id(); 922 _dw_main_thread = dw_thread_id();
981 923
994 */ 936 */
995 dw_event_wait(_dw_main_event, 100); 937 dw_event_wait(_dw_main_event, 100);
996 938
997 } while(_dw_main_active); 939 } while(_dw_main_active);
998 _dw_main_thread = -1; 940 _dw_main_thread = -1;
999 #endif
1000 } 941 }
1001 942
1002 /* 943 /*
1003 * Causes running dw_main() to return. 944 * Causes running dw_main() to return.
1004 */ 945 */
1005 void API dw_main_quit(void) 946 void API dw_main_quit(void)
1006 { 947 {
1007 #ifndef _DW_EVENT_THREADING
1008 _dw_main_active = FALSE; 948 _dw_main_active = FALSE;
1009 #endif
1010 dw_event_post(_dw_main_event); 949 dw_event_post(_dw_main_event);
1011 } 950 }
1012 951
1013 /* 952 /*
1014 * Runs a message loop for Dynamic Windows, for a period of milliseconds. 953 * Runs a message loop for Dynamic Windows, for a period of milliseconds.
1017 */ 956 */
1018 void API dw_main_sleep(int milliseconds) 957 void API dw_main_sleep(int milliseconds)
1019 { 958 {
1020 JNIEnv *env; 959 JNIEnv *env;
1021 960
1022 #ifndef _DW_EVENT_THREADING
1023 /* If we are in an event callback from dw_main() ... 961 /* If we are in an event callback from dw_main() ...
1024 * we need to continue handling events from the UI. 962 * we need to continue handling events from the UI.
1025 */ 963 */
1026 if(_dw_main_thread == dw_thread_id()) 964 if(_dw_main_thread == dw_thread_id())
1027 { 965 {
1048 986
1049 gettimeofday(&tv, NULL); 987 gettimeofday(&tv, NULL);
1050 988
1051 } while(_dw_main_active && (difference = ((tv.tv_sec - start.tv_sec)*1000) + ((tv.tv_usec - start.tv_usec)/1000)) <= milliseconds); 989 } while(_dw_main_active && (difference = ((tv.tv_sec - start.tv_sec)*1000) + ((tv.tv_usec - start.tv_usec)/1000)) <= milliseconds);
1052 } 990 }
1053 else 991 else if((env = (JNIEnv *)pthread_getspecific(_dw_env_key)))
1054 #endif
1055 if((env = (JNIEnv *)pthread_getspecific(_dw_env_key)))
1056 { 992 {
1057 // First get the class that contains the method you need to call 993 // First get the class that contains the method you need to call
1058 jclass clazz = _dw_find_class(env, DW_CLASS_NAME); 994 jclass clazz = _dw_find_class(env, DW_CLASS_NAME);
1059 // Get the method that you want to call 995 // Get the method that you want to call
1060 jmethodID mainSleep = env->GetMethodID(clazz, "mainSleep", 996 jmethodID mainSleep = env->GetMethodID(clazz, "mainSleep",
1068 /* 1004 /*
1069 * Processes a single message iteration and returns. 1005 * Processes a single message iteration and returns.
1070 */ 1006 */
1071 void API dw_main_iteration(void) 1007 void API dw_main_iteration(void)
1072 { 1008 {
1073 #ifndef _DW_EVENT_THREADING
1074 if(_dw_main_thread == dw_thread_id()) 1009 if(_dw_main_thread == dw_thread_id())
1075 { 1010 {
1076 void *params[_DW_EVENT_PARAM_SIZE]; 1011 void *params[_DW_EVENT_PARAM_SIZE];
1077 1012
1078 /* Dequeue a single pending event */ 1013 /* Dequeue a single pending event */
1079 if (_dw_dequeue_event(params)) 1014 if (_dw_dequeue_event(params))
1080 _dw_event_handler2(params); 1015 _dw_event_handler2(params);
1081 } 1016 }
1082 else 1017 else
1083 #endif
1084 /* If we sleep for 0 milliseconds... we will drop out 1018 /* If we sleep for 0 milliseconds... we will drop out
1085 * of the loop at the first idle moment 1019 * of the loop at the first idle moment
1086 */ 1020 */
1087 dw_main_sleep(0); 1021 dw_main_sleep(0);
1088 } 1022 }
1089 1023
1090 /* 1024 /*
1091 * Cleanly terminates a DW session, should be signal handler safe. 1025 * Cleanly terminates a DW session, should be signal handler safe.
1092 * Parameters: 1026 * Parameters: