comparison android/dw.cpp @ 2474:a13e6db064f4

Android: Implement thread, semaphore, shared memory API functions. Implement dwmain() entrypoint and include dwtest.c in the build. Like on iOS dw_main() doesn't actually run the message loop... So wait for dw_main() to be called and return to the JVM.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Mon, 19 Apr 2021 23:06:25 +0000
parents aa420e366b2b
children 16d195d46f2a
comparison
equal deleted inserted replaced
2473:aa420e366b2b 2474:a13e6db064f4
3 * A GTK like GUI implementation of the Android GUI. 3 * A GTK like GUI implementation of the Android GUI.
4 * 4 *
5 * (C) 2011-2021 Brian Smith <brian@dbsoft.org> 5 * (C) 2011-2021 Brian Smith <brian@dbsoft.org>
6 * (C) 2011-2021 Mark Hessling <mark@rexx.org> 6 * (C) 2011-2021 Mark Hessling <mark@rexx.org>
7 * 7 *
8 * Compile with $CC -I. -D__ANDROID__ template/dw.c
9 *
10 */ 8 */
11 9
12 #include <jni.h> 10 #include <jni.h>
13 #include "dw.h" 11 #include "dw.h"
14 #include <stdlib.h> 12 #include <stdlib.h>
15 #include <string.h> 13 #include <string.h>
14 #include <sys/utsname.h>
15 #include <sys/socket.h>
16 #include <sys/un.h>
17 #include <sys/mman.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <dlfcn.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #if defined(__ANDROID__) && (__ANDROID_API__+0) < 21
25 #include <sys/syscall.h>
26 #endif
27
28 #if defined(__ANDROID__) && (__ANDROID_API__+0) < 21
29 /* Until Android API version 21 NDK does not define getsid wrapper in libc, although there is the corresponding syscall */
30 inline pid_t getsid(pid_t pid)
31 {
32 return static_cast< pid_t >(::syscall(__NR_getsid, pid));
33 }
34 #endif
16 35
17 #ifdef __cplusplus 36 #ifdef __cplusplus
18 extern "C" { 37 extern "C" {
19 #endif 38 #endif
20 39
40 static pthread_key_t _dw_event_key;
41 static HEV _dw_main_event;
42
43 /* Call the dwmain entry point, Android has no args, so just pass the app path */
44 void _dw_main_launch(char *arg)
45 {
46 char *argv[2] = { arg, NULL };
47 dwmain(1, argv);
48 }
49
50 /* Called when DWindows activity starts up... so we create a thread
51 * to call the dwmain() entrypoint... then we wait for dw_main()
52 * to be called and return.
53 * Parameters:
54 * path: The path to the Android app.
55 */
21 JNIEXPORT jstring JNICALL 56 JNIEXPORT jstring JNICALL
22 Java_org_dbsoft_dwindows_dwtest_DWindows_stringFromJNI( 57 Java_org_dbsoft_dwindows_dwtest_DWindows_dwindowsInit(
23 JNIEnv* env, 58 JNIEnv* env, jobject obj, jstring path) {
24 jobject /* this */) { 59 char *arg = strdup(env->GetStringUTFChars((jstring) path, NULL));
25 char hello[] = "Hello from C++"; 60
26 return env->NewStringUTF(hello); 61 /* Create the dwmain event */
62 _dw_main_event = dw_event_new();
63
64 /* Launch the new thread to execute dwmain() */
65 dw_thread_new((void *)_dw_main_launch, arg, 0);
66
67 /* Wait until dwmain() calls dw_main() then return */
68 dw_event_wait(_dw_main_event, DW_TIMEOUT_INFINITE);
69 #if 0
70 // Construct a String
71 jstring jstr = env->NewStringUTF("This string comes from JNI");
72 // First get the class that contains the method you need to call
73 jclass clazz = env->FindClass("org/dbsoft/dwindows/dwtest/DWindows");
74 // Get the method that you want to call
75 jmethodID dwindowsInit = env->GetMethodID(clazz, "dwindowsInit", "(Ljava/lang/String;)V");
76 // Call the method on the object
77 jobject result = env->CallObjectMethod(obj, jstr, dwindowsInit);
78 // Get a C-style string
79 const char* str = env->GetStringUTFChars((jstring) result, NULL);
80 printf("%s\n", str);
81 // Clean up
82 env->ReleaseStringUTFChars(jstr, str);
83 #endif
84 return env->NewStringUTF("Hello from JNI!");
27 } 85 }
28 86
29 /* Implement these to get and set the Box* pointer on the widget handle */ 87 /* Implement these to get and set the Box* pointer on the widget handle */
30 void *_dw_window_pointer_get(HWND handle) 88 void *_dw_window_pointer_get(HWND handle)
31 { 89 {
260 /* 318 /*
261 * Runs a message loop for Dynamic Windows. 319 * Runs a message loop for Dynamic Windows.
262 */ 320 */
263 void API dw_main(void) 321 void API dw_main(void)
264 { 322 {
323 /* Post the event so dwindowsInit() will return...
324 * allowing the app to start handling events.
325 */
326 dw_event_post(_dw_main_event);
327 dw_event_reset(_dw_main_event);
328
329 /* We don't actually run a loop here,
330 * we launched a new thread to run the loop there.
331 * Just wait for dw_main_quit() on the DWMainEvent.
332 */
333 dw_event_wait(_dw_main_event, DW_TIMEOUT_INFINITE);
265 } 334 }
266 335
267 /* 336 /*
268 * Causes running dw_main() to return. 337 * Causes running dw_main() to return.
269 */ 338 */
270 void API dw_main_quit(void) 339 void API dw_main_quit(void)
271 { 340 {
341 dw_event_post(_dw_main_event);
272 } 342 }
273 343
274 /* 344 /*
275 * Runs a message loop for Dynamic Windows, for a period of milliseconds. 345 * Runs a message loop for Dynamic Windows, for a period of milliseconds.
276 * Parameters: 346 * Parameters:
3192 */ 3262 */
3193 void API dw_signal_disconnect_by_data(HWND window, void *data) 3263 void API dw_signal_disconnect_by_data(HWND window, void *data)
3194 { 3264 {
3195 } 3265 }
3196 3266
3267 void _dw_strlwr(char *buf)
3268 {
3269 int z, len = strlen(buf);
3270
3271 for(z=0;z<len;z++)
3272 {
3273 if(buf[z] >= 'A' && buf[z] <= 'Z')
3274 buf[z] -= 'A' - 'a';
3275 }
3276 }
3277
3197 /* Open a shared library and return a handle. 3278 /* Open a shared library and return a handle.
3198 * Parameters: 3279 * Parameters:
3199 * name: Base name of the shared library. 3280 * name: Base name of the shared library.
3200 * handle: Pointer to a module handle, 3281 * handle: Pointer to a module handle,
3201 * will be filled in with the handle. 3282 * will be filled in with the handle.
3202 * Returns: 3283 */
3203 * DW_ERROR_NONE (0) on success.
3204 */
3205 int API dw_module_load(const char *name, HMOD *handle) 3284 int API dw_module_load(const char *name, HMOD *handle)
3206 { 3285 {
3207 return DW_ERROR_UNKNOWN; 3286 int len;
3287 char *newname;
3288 char errorbuf[1025] = {0};
3289
3290
3291 if(!handle)
3292 return -1;
3293
3294 if((len = strlen(name)) == 0)
3295 return -1;
3296
3297 /* Lenth + "lib" + ".so" + NULL */
3298 newname = (char *)malloc(len + 7);
3299
3300 if(!newname)
3301 return -1;
3302
3303 sprintf(newname, "lib%s.so", name);
3304 _dw_strlwr(newname);
3305
3306 *handle = dlopen(newname, RTLD_NOW);
3307 if(*handle == NULL)
3308 {
3309 strncpy(errorbuf, dlerror(), 1024);
3310 printf("%s\n", errorbuf);
3311 sprintf(newname, "lib%s.so", name);
3312 *handle = dlopen(newname, RTLD_NOW);
3313 }
3314
3315 free(newname);
3316
3317 return (NULL == *handle) ? -1 : 0;
3208 } 3318 }
3209 3319
3210 /* Queries the address of a symbol within open handle. 3320 /* Queries the address of a symbol within open handle.
3211 * Parameters: 3321 * Parameters:
3212 * handle: Module handle returned by dw_module_load() 3322 * handle: Module handle returned by dw_module_load()
3213 * name: Name of the symbol you want the address of. 3323 * name: Name of the symbol you want the address of.
3214 * func: A pointer to a function pointer, to obtain 3324 * func: A pointer to a function pointer, to obtain
3215 * the address. 3325 * the address.
3216 * Returns:
3217 * DW_ERROR_NONE (0) on success.
3218 */ 3326 */
3219 int API dw_module_symbol(HMOD handle, const char *name, void**func) 3327 int API dw_module_symbol(HMOD handle, const char *name, void**func)
3220 { 3328 {
3221 return DW_ERROR_UNKNOWN; 3329 if(!func || !name)
3330 return -1;
3331
3332 if(strlen(name) == 0)
3333 return -1;
3334
3335 *func = (void*)dlsym(handle, name);
3336 return (NULL == *func);
3222 } 3337 }
3223 3338
3224 /* Frees the shared library previously opened. 3339 /* Frees the shared library previously opened.
3225 * Parameters: 3340 * Parameters:
3226 * handle: Module handle returned by dw_module_load() 3341 * handle: Module handle returned by dw_module_load()
3227 * Returns:
3228 * DW_ERROR_NONE (0) on success.
3229 */ 3342 */
3230 int API dw_module_close(HMOD handle) 3343 int API dw_module_close(HMOD handle)
3231 { 3344 {
3232 return DW_ERROR_GENERAL; 3345 if(handle)
3233 } 3346 return dlclose(handle);
3234 3347 return 0;
3235 /* 3348 }
3236 * Returns the handle to an unnamed mutex semaphore or NULL on error. 3349
3350 /*
3351 * Returns the handle to an unnamed mutex semaphore.
3237 */ 3352 */
3238 HMTX API dw_mutex_new(void) 3353 HMTX API dw_mutex_new(void)
3239 { 3354 {
3240 return NULL; 3355 HMTX mutex = (HMTX)malloc(sizeof(pthread_mutex_t));
3356
3357 pthread_mutex_init(mutex, NULL);
3358 return mutex;
3241 } 3359 }
3242 3360
3243 /* 3361 /*
3244 * Closes a semaphore created by dw_mutex_new(). 3362 * Closes a semaphore created by dw_mutex_new().
3245 * Parameters: 3363 * Parameters:
3246 * mutex: The handle to the mutex returned by dw_mutex_new(). 3364 * mutex: The handle to the mutex returned by dw_mutex_new().
3247 */ 3365 */
3248 void API dw_mutex_close(HMTX mutex) 3366 void API dw_mutex_close(HMTX mutex)
3249 { 3367 {
3368 if(mutex)
3369 {
3370 pthread_mutex_destroy(mutex);
3371 free(mutex);
3372 }
3250 } 3373 }
3251 3374
3252 /* 3375 /*
3253 * Tries to gain access to the semaphore, if it can't it blocks. 3376 * Tries to gain access to the semaphore, if it can't it blocks.
3254 * Parameters: 3377 * Parameters:
3255 * mutex: The handle to the mutex returned by dw_mutex_new(). 3378 * mutex: The handle to the mutex returned by dw_mutex_new().
3256 */ 3379 */
3257 void API dw_mutex_lock(HMTX mutex) 3380 void API dw_mutex_lock(HMTX mutex)
3258 { 3381 {
3259 #if 0
3260 /* We need to handle locks from the main thread differently... 3382 /* We need to handle locks from the main thread differently...
3261 * since we can't stop message processing... otherwise we 3383 * since we can't stop message processing... otherwise we
3262 * will deadlock... so try to acquire the lock and continue 3384 * will deadlock... so try to acquire the lock and continue
3263 * processing messages in between tries. 3385 * processing messages in between tries.
3264 */ 3386 */
3265 if(_dw_thread == dw_thread_id()) 3387 #if 0 /* TODO: Not sure how to do this on Android yet */
3388 if(_dw_thread == pthread_self())
3266 { 3389 {
3267 while(/* Attempt to lock the mutex */) 3390 while(pthread_mutex_trylock(mutex) != 0)
3268 { 3391 {
3269 /* Process any pending events */ 3392 /* Process any pending events */
3270 while(dw_main_iteration()) 3393 if(g_main_context_pending(NULL))
3271 { 3394 {
3272 /* Just loop */ 3395 do
3396 {
3397 g_main_context_iteration(NULL, FALSE);
3398 }
3399 while(g_main_context_pending(NULL));
3400 }
3401 else
3402 sched_yield();
3403 }
3404 }
3405 else
3406 #endif
3407 {
3408 pthread_mutex_lock(mutex);
3409 }
3410 }
3411
3412 /*
3413 * Tries to gain access to the semaphore.
3414 * Parameters:
3415 * mutex: The handle to the mutex returned by dw_mutex_new().
3416 * Returns:
3417 * DW_ERROR_NONE on success, DW_ERROR_TIMEOUT if it is already locked.
3418 */
3419 int API dw_mutex_trylock(HMTX mutex)
3420 {
3421 if(pthread_mutex_trylock(mutex) == 0)
3422 return DW_ERROR_NONE;
3423 return DW_ERROR_TIMEOUT;
3424 }
3425
3426 /*
3427 * Reliquishes the access to the semaphore.
3428 * Parameters:
3429 * mutex: The handle to the mutex returned by dw_mutex_new().
3430 */
3431 void API dw_mutex_unlock(HMTX mutex)
3432 {
3433 pthread_mutex_unlock(mutex);
3434 }
3435
3436 /*
3437 * Returns the handle to an unnamed event semaphore.
3438 */
3439 HEV API dw_event_new(void)
3440 {
3441 HEV eve = (HEV)malloc(sizeof(struct _dw_unix_event));
3442
3443 if(!eve)
3444 return NULL;
3445
3446 /* We need to be careful here, mutexes on Linux are
3447 * FAST by default but are error checking on other
3448 * systems such as FreeBSD and OS/2, perhaps others.
3449 */
3450 pthread_mutex_init (&(eve->mutex), NULL);
3451 pthread_mutex_lock (&(eve->mutex));
3452 pthread_cond_init (&(eve->event), NULL);
3453
3454 pthread_mutex_unlock (&(eve->mutex));
3455 eve->alive = 1;
3456 eve->posted = 0;
3457
3458 return eve;
3459 }
3460
3461 /*
3462 * Resets a semaphore created by dw_event_new().
3463 * Parameters:
3464 * eve: The handle to the event returned by dw_event_new().
3465 */
3466 int API dw_event_reset (HEV eve)
3467 {
3468 if(!eve)
3469 return DW_ERROR_NON_INIT;
3470
3471 pthread_mutex_lock (&(eve->mutex));
3472 pthread_cond_broadcast (&(eve->event));
3473 pthread_cond_init (&(eve->event), NULL);
3474 eve->posted = 0;
3475 pthread_mutex_unlock (&(eve->mutex));
3476 return DW_ERROR_NONE;
3477 }
3478
3479 /*
3480 * Posts a semaphore created by dw_event_new(). Causing all threads
3481 * waiting on this event in dw_event_wait to continue.
3482 * Parameters:
3483 * eve: The handle to the event returned by dw_event_new().
3484 */
3485 int API dw_event_post (HEV eve)
3486 {
3487 if(!eve)
3488 return DW_ERROR_NON_INIT;
3489
3490 pthread_mutex_lock (&(eve->mutex));
3491 pthread_cond_broadcast (&(eve->event));
3492 eve->posted = 1;
3493 pthread_mutex_unlock (&(eve->mutex));
3494 return DW_ERROR_NONE;
3495 }
3496
3497 /*
3498 * Waits on a semaphore created by dw_event_new(), until the
3499 * event gets posted or until the timeout expires.
3500 * Parameters:
3501 * eve: The handle to the event returned by dw_event_new().
3502 */
3503 int API dw_event_wait(HEV eve, unsigned long timeout)
3504 {
3505 int rc;
3506
3507 if(!eve)
3508 return DW_ERROR_NON_INIT;
3509
3510 pthread_mutex_lock (&(eve->mutex));
3511
3512 if(eve->posted)
3513 {
3514 pthread_mutex_unlock (&(eve->mutex));
3515 return DW_ERROR_NONE;
3516 }
3517
3518 if(timeout != -1)
3519 {
3520 struct timeval now;
3521 struct timespec timeo;
3522
3523 gettimeofday(&now, 0);
3524 timeo.tv_sec = now.tv_sec + (timeout / 1000);
3525 timeo.tv_nsec = now.tv_usec * 1000;
3526 rc = pthread_cond_timedwait(&(eve->event), &(eve->mutex), &timeo);
3527 }
3528 else
3529 rc = pthread_cond_wait(&(eve->event), &(eve->mutex));
3530
3531 pthread_mutex_unlock (&(eve->mutex));
3532 if(!rc)
3533 return DW_ERROR_NONE;
3534 if(rc == ETIMEDOUT)
3535 return DW_ERROR_TIMEOUT;
3536 return DW_ERROR_GENERAL;
3537 }
3538
3539 /*
3540 * Closes a semaphore created by dw_event_new().
3541 * Parameters:
3542 * eve: The handle to the event returned by dw_event_new().
3543 */
3544 int API dw_event_close(HEV *eve)
3545 {
3546 if(!eve || !(*eve))
3547 return DW_ERROR_NON_INIT;
3548
3549 pthread_mutex_lock (&((*eve)->mutex));
3550 pthread_cond_destroy (&((*eve)->event));
3551 pthread_mutex_unlock (&((*eve)->mutex));
3552 pthread_mutex_destroy (&((*eve)->mutex));
3553 free(*eve);
3554 *eve = NULL;
3555
3556 return DW_ERROR_NONE;
3557 }
3558
3559 struct _dw_seminfo {
3560 int fd;
3561 int waiting;
3562 };
3563
3564 static void _dw_handle_sem(int *tmpsock)
3565 {
3566 fd_set rd;
3567 struct _dw_seminfo *array = (struct _dw_seminfo *)malloc(sizeof(struct _dw_seminfo));
3568 int listenfd = tmpsock[0];
3569 int bytesread, connectcount = 1, maxfd, z, posted = 0;
3570 char command;
3571 sigset_t mask;
3572
3573 sigfillset(&mask); /* Mask all allowed signals */
3574 pthread_sigmask(SIG_BLOCK, &mask, NULL);
3575
3576 /* problems */
3577 if(tmpsock[1] == -1)
3578 {
3579 free(array);
3580 return;
3581 }
3582
3583 array[0].fd = tmpsock[1];
3584 array[0].waiting = 0;
3585
3586 /* Free the memory allocated in dw_named_event_new. */
3587 free(tmpsock);
3588
3589 while(1)
3590 {
3591 FD_ZERO(&rd);
3592 FD_SET(listenfd, &rd);
3593 int DW_UNUSED(result);
3594
3595 maxfd = listenfd;
3596
3597 /* Added any connections to the named event semaphore */
3598 for(z=0;z<connectcount;z++)
3599 {
3600 if(array[z].fd > maxfd)
3601 maxfd = array[z].fd;
3602
3603 FD_SET(array[z].fd, &rd);
3604 }
3605
3606 if(select(maxfd+1, &rd, NULL, NULL, NULL) == -1)
3607 {
3608 free(array);
3609 return;
3610 }
3611
3612 if(FD_ISSET(listenfd, &rd))
3613 {
3614 struct _dw_seminfo *newarray;
3615 int newfd = accept(listenfd, 0, 0);
3616
3617 if(newfd > -1)
3618 {
3619 /* Add new connections to the set */
3620 newarray = (struct _dw_seminfo *)malloc(sizeof(struct _dw_seminfo)*(connectcount+1));
3621 memcpy(newarray, array, sizeof(struct _dw_seminfo)*(connectcount));
3622
3623 newarray[connectcount].fd = newfd;
3624 newarray[connectcount].waiting = 0;
3625
3626 connectcount++;
3627
3628 /* Replace old array with new one */
3629 free(array);
3630 array = newarray;
3631 }
3632 }
3633
3634 /* Handle any events posted to the semaphore */
3635 for(z=0;z<connectcount;z++)
3636 {
3637 if(FD_ISSET(array[z].fd, &rd))
3638 {
3639 if((bytesread = read(array[z].fd, &command, 1)) < 1)
3640 {
3641 struct _dw_seminfo *newarray;
3642
3643 /* Remove this connection from the set */
3644 newarray = (struct _dw_seminfo *)malloc(sizeof(struct _dw_seminfo)*(connectcount-1));
3645 if(!z)
3646 memcpy(newarray, &array[1], sizeof(struct _dw_seminfo)*(connectcount-1));
3647 else
3648 {
3649 memcpy(newarray, array, sizeof(struct _dw_seminfo)*z);
3650 if(z!=(connectcount-1))
3651 memcpy(&newarray[z], &array[z+1], sizeof(struct _dw_seminfo)*(z-connectcount-1));
3652 }
3653 connectcount--;
3654
3655 /* Replace old array with new one */
3656 free(array);
3657 array = newarray;
3658 }
3659 else if(bytesread == 1)
3660 {
3661 switch(command)
3662 {
3663 case 0:
3664 {
3665 /* Reset */
3666 posted = 0;
3667 }
3668 break;
3669 case 1:
3670 /* Post */
3671 {
3672 int s;
3673 char tmp = (char)0;
3674
3675 posted = 1;
3676
3677 for(s=0;s<connectcount;s++)
3678 {
3679 /* The semaphore has been posted so
3680 * we tell all the waiting threads to
3681 * continue.
3682 */
3683 if(array[s].waiting)
3684 result = write(array[s].fd, &tmp, 1);
3685 }
3686 }
3687 break;
3688 case 2:
3689 /* Wait */
3690 {
3691 char tmp = (char)0;
3692
3693 array[z].waiting = 1;
3694
3695 /* If we are posted exit immeditately */
3696 if(posted)
3697 result = write(array[z].fd, &tmp, 1);
3698 }
3699 break;
3700 case 3:
3701 {
3702 /* Done Waiting */
3703 array[z].waiting = 0;
3704 }
3705 break;
3706 }
3707 }
3273 } 3708 }
3274 } 3709 }
3275 } 3710 }
3276 else 3711 }
3277 { 3712
3278 /* Lock the mutex */ 3713 /* Using domain sockets on unix for IPC */
3279 }
3280 #endif
3281 }
3282
3283 /*
3284 * Tries to gain access to the semaphore.
3285 * Parameters:
3286 * mutex: The handle to the mutex returned by dw_mutex_new().
3287 * Returns:
3288 * DW_ERROR_NONE on success, DW_ERROR_TIMEOUT if it is already locked.
3289 */
3290 int API dw_mutex_trylock(HMTX mutex)
3291 {
3292 return DW_ERROR_GENERAL;
3293 }
3294
3295 /*
3296 * Reliquishes the access to the semaphore.
3297 * Parameters:
3298 * mutex: The handle to the mutex returned by dw_mutex_new().
3299 */
3300 void API dw_mutex_unlock(HMTX mutex)
3301 {
3302 }
3303
3304 /*
3305 * Returns the handle to an unnamed event semaphore or NULL on error.
3306 */
3307 HEV API dw_event_new(void)
3308 {
3309 return NULL;
3310 }
3311
3312 /*
3313 * Resets a semaphore created by dw_event_new().
3314 * Parameters:
3315 * eve: The handle to the event returned by dw_event_new().
3316 * Returns:
3317 * DW_ERROR_NONE (0) on success.
3318 */
3319 int API dw_event_reset (HEV eve)
3320 {
3321 return DW_ERROR_GENERAL;
3322 }
3323
3324 /*
3325 * Posts a semaphore created by dw_event_new(). Causing all threads
3326 * waiting on this event in dw_event_wait to continue.
3327 * Parameters:
3328 * eve: The handle to the event returned by dw_event_new().
3329 * Returns:
3330 * DW_ERROR_NONE (0) on success.
3331 */
3332 int API dw_event_post (HEV eve)
3333 {
3334 return DW_ERROR_GENERAL;
3335 }
3336
3337 /*
3338 * Waits on a semaphore created by dw_event_new(), until the
3339 * event gets posted or until the timeout expires.
3340 * Parameters:
3341 * eve: The handle to the event returned by dw_event_new().
3342 * timeout: Number of milliseconds before timing out
3343 * or -1 if indefinite.
3344 * Returns:
3345 * DW_ERROR_NONE (0) on success.
3346 * DW_ERROR_TIMEOUT (2) if the timeout has expired.
3347 * Other values on other error.
3348 */
3349 int API dw_event_wait(HEV eve, unsigned long timeout)
3350 {
3351 return DW_ERROR_GENERAL;
3352 }
3353
3354 /*
3355 * Closes a semaphore created by dw_event_new().
3356 * Parameters:
3357 * eve: The handle to the event returned by dw_event_new().
3358 * Returns:
3359 * DW_ERROR_NONE (0) on success.
3360 */
3361 int API dw_event_close(HEV *eve)
3362 {
3363 return DW_ERROR_GENERAL;
3364 }
3365
3366 /* Create a named event semaphore which can be 3714 /* Create a named event semaphore which can be
3367 * opened from other processes. 3715 * opened from other processes.
3368 * Parameters: 3716 * Parameters:
3717 * eve: Pointer to an event handle to receive handle.
3369 * name: Name given to semaphore which can be opened 3718 * name: Name given to semaphore which can be opened
3370 * by other processes. 3719 * by other processes.
3371 * Returns:
3372 * Handle to event semaphore or NULL on error.
3373 */ 3720 */
3374 HEV API dw_named_event_new(const char *name) 3721 HEV API dw_named_event_new(const char *name)
3375 { 3722 {
3376 return NULL; 3723 struct sockaddr_un un;
3724 int ev, *tmpsock = (int *)malloc(sizeof(int)*2);
3725 DWTID dwthread;
3726
3727 if(!tmpsock)
3728 return NULL;
3729
3730 tmpsock[0] = socket(AF_UNIX, SOCK_STREAM, 0);
3731 ev = socket(AF_UNIX, SOCK_STREAM, 0);
3732 memset(&un, 0, sizeof(un));
3733 un.sun_family=AF_UNIX;
3734 mkdir("/tmp/.dw", S_IWGRP|S_IWOTH);
3735 strcpy(un.sun_path, "/tmp/.dw/");
3736 strcat(un.sun_path, name);
3737
3738 /* just to be safe, this should be changed
3739 * to support multiple instances.
3740 */
3741 remove(un.sun_path);
3742
3743 bind(tmpsock[0], (struct sockaddr *)&un, sizeof(un));
3744 listen(tmpsock[0], 0);
3745 connect(ev, (struct sockaddr *)&un, sizeof(un));
3746 tmpsock[1] = accept(tmpsock[0], 0, 0);
3747
3748 if(tmpsock[0] < 0 || tmpsock[1] < 0 || ev < 0)
3749 {
3750 if(tmpsock[0] > -1)
3751 close(tmpsock[0]);
3752 if(tmpsock[1] > -1)
3753 close(tmpsock[1]);
3754 if(ev > -1)
3755 close(ev);
3756 free(tmpsock);
3757 return NULL;
3758 }
3759
3760 /* Create a thread to handle this event semaphore */
3761 pthread_create(&dwthread, NULL, (void *(*)(void *))_dw_handle_sem, (void *)tmpsock);
3762 return (HEV)DW_INT_TO_POINTER(ev);
3377 } 3763 }
3378 3764
3379 /* Open an already existing named event semaphore. 3765 /* Open an already existing named event semaphore.
3380 * Parameters: 3766 * Parameters:
3767 * eve: Pointer to an event handle to receive handle.
3381 * name: Name given to semaphore which can be opened 3768 * name: Name given to semaphore which can be opened
3382 * by other processes. 3769 * by other processes.
3383 * Returns:
3384 * Handle to event semaphore or NULL on error.
3385 */ 3770 */
3386 HEV API dw_named_event_get(const char *name) 3771 HEV API dw_named_event_get(const char *name)
3387 { 3772 {
3388 return NULL; 3773 struct sockaddr_un un;
3774 int ev = socket(AF_UNIX, SOCK_STREAM, 0);
3775 if(ev < 0)
3776 return NULL;
3777
3778 un.sun_family=AF_UNIX;
3779 mkdir("/tmp/.dw", S_IWGRP|S_IWOTH);
3780 strcpy(un.sun_path, "/tmp/.dw/");
3781 strcat(un.sun_path, name);
3782 connect(ev, (struct sockaddr *)&un, sizeof(un));
3783 return (HEV)DW_INT_TO_POINTER(ev);
3389 } 3784 }
3390 3785
3391 /* Resets the event semaphore so threads who call wait 3786 /* Resets the event semaphore so threads who call wait
3392 * on this semaphore will block. 3787 * on this semaphore will block.
3393 * Parameters: 3788 * Parameters:
3394 * eve: Handle to the semaphore obtained by 3789 * eve: Handle to the semaphore obtained by
3395 * an get or new call. 3790 * an open or create call.
3396 * Returns:
3397 * DW_ERROR_NONE (0) on success.
3398 */ 3791 */
3399 int API dw_named_event_reset(HEV eve) 3792 int API dw_named_event_reset(HEV eve)
3400 { 3793 {
3794 /* signal reset */
3795 char tmp = (char)0;
3796
3797 if(DW_POINTER_TO_INT(eve) < 0)
3798 return DW_ERROR_NONE;
3799
3800 if(write(DW_POINTER_TO_INT(eve), &tmp, 1) == 1)
3801 return DW_ERROR_NONE;
3401 return DW_ERROR_GENERAL; 3802 return DW_ERROR_GENERAL;
3402 } 3803 }
3403 3804
3404 /* Sets the posted state of an event semaphore, any threads 3805 /* Sets the posted state of an event semaphore, any threads
3405 * waiting on the semaphore will no longer block. 3806 * waiting on the semaphore will no longer block.
3406 * Parameters: 3807 * Parameters:
3407 * eve: Handle to the semaphore obtained by 3808 * eve: Handle to the semaphore obtained by
3408 * an get or new call. 3809 * an open or create call.
3409 * Returns:
3410 * DW_ERROR_NONE (0) on success.
3411 */ 3810 */
3412 int API dw_named_event_post(HEV eve) 3811 int API dw_named_event_post(HEV eve)
3413 { 3812 {
3813
3814 /* signal post */
3815 char tmp = (char)1;
3816
3817 if(DW_POINTER_TO_INT(eve) < 0)
3818 return DW_ERROR_NONE;
3819
3820 if(write(DW_POINTER_TO_INT(eve), &tmp, 1) == 1)
3821 return DW_ERROR_NONE;
3414 return DW_ERROR_GENERAL; 3822 return DW_ERROR_GENERAL;
3415 } 3823 }
3416 3824
3417 /* Waits on the specified semaphore until it becomes 3825 /* Waits on the specified semaphore until it becomes
3418 * posted, or returns immediately if it already is posted. 3826 * posted, or returns immediately if it already is posted.
3419 * Parameters: 3827 * Parameters:
3420 * eve: Handle to the semaphore obtained by 3828 * eve: Handle to the semaphore obtained by
3421 * an get or new call. 3829 * an open or create call.
3422 * timeout: Number of milliseconds before timing out 3830 * timeout: Number of milliseconds before timing out
3423 * or -1 if indefinite. 3831 * or -1 if indefinite.
3424 * Returns:
3425 * DW_ERROR_NONE (0) on success.
3426 */ 3832 */
3427 int API dw_named_event_wait(HEV eve, unsigned long timeout) 3833 int API dw_named_event_wait(HEV eve, unsigned long timeout)
3428 { 3834 {
3429 return DW_ERROR_UNKNOWN; 3835 fd_set rd;
3836 struct timeval tv, *useme = NULL;
3837 int retval = 0;
3838 char tmp;
3839
3840 if(DW_POINTER_TO_INT(eve) < 0)
3841 return DW_ERROR_NON_INIT;
3842
3843 /* Set the timout or infinite */
3844 if(timeout != -1)
3845 {
3846 tv.tv_sec = timeout / 1000;
3847 tv.tv_usec = timeout % 1000;
3848
3849 useme = &tv;
3850 }
3851
3852 FD_ZERO(&rd);
3853 FD_SET(DW_POINTER_TO_INT(eve), &rd);
3854
3855 /* Signal wait */
3856 tmp = (char)2;
3857 retval = write(DW_POINTER_TO_INT(eve), &tmp, 1);
3858
3859 if(retval == 1)
3860 retval = select(DW_POINTER_TO_INT(eve)+1, &rd, NULL, NULL, useme);
3861
3862 /* Signal done waiting. */
3863 tmp = (char)3;
3864 if(retval == 1)
3865 retval = write(DW_POINTER_TO_INT(eve), &tmp, 1);
3866
3867 if(retval == 0)
3868 return DW_ERROR_TIMEOUT;
3869 else if(retval == -1)
3870 return DW_ERROR_INTERRUPT;
3871
3872 /* Clear the entry from the pipe so
3873 * we don't loop endlessly. :)
3874 */
3875 if(read(DW_POINTER_TO_INT(eve), &tmp, 1) == 1)
3876 return DW_ERROR_NONE;
3877 return DW_ERROR_GENERAL;
3430 } 3878 }
3431 3879
3432 /* Release this semaphore, if there are no more open 3880 /* Release this semaphore, if there are no more open
3433 * handles on this semaphore the semaphore will be destroyed. 3881 * handles on this semaphore the semaphore will be destroyed.
3434 * Parameters: 3882 * Parameters:
3435 * eve: Handle to the semaphore obtained by 3883 * eve: Handle to the semaphore obtained by
3436 * an get or new call. 3884 * an open or create call.
3437 * Returns:
3438 * DW_ERROR_NONE (0) on success.
3439 */ 3885 */
3440 int API dw_named_event_close(HEV eve) 3886 int API dw_named_event_close(HEV eve)
3441 { 3887 {
3442 return DW_ERROR_UNKNOWN; 3888 /* Finally close the domain socket,
3889 * cleanup will continue in _dw_handle_sem.
3890 */
3891 close(DW_POINTER_TO_INT(eve));
3892 return DW_ERROR_NONE;
3893 }
3894
3895 /*
3896 * Generally an internal function called from a newly created
3897 * thread to setup the Dynamic Windows environment for the thread.
3898 * However it is exported so language bindings can call it when
3899 * they create threads that require access to Dynamic Windows.
3900 */
3901 void API _dw_init_thread(void)
3902 {
3903 HEV event = dw_event_new();
3904
3905 pthread_setspecific(_dw_event_key, event);
3906 }
3907
3908 /*
3909 * Generally an internal function called from a terminating
3910 * thread to cleanup the Dynamic Windows environment for the thread.
3911 * However it is exported so language bindings can call it when
3912 * they exit threads that require access to Dynamic Windows.
3913 */
3914 void API _dw_deinit_thread(void)
3915 {
3916 HEV event;
3917
3918 if((event = (HEV)pthread_getspecific(_dw_event_key)))
3919 dw_event_close(&event);
3920 }
3921
3922 /*
3923 * Setup thread independent color sets.
3924 */
3925 void _dwthreadstart(void *data)
3926 {
3927 void (*threadfunc)(void *) = NULL;
3928 void **tmp = (void **)data;
3929
3930 threadfunc = (void (*)(void *))tmp[0];
3931
3932 /* Initialize colors */
3933 _dw_init_thread();
3934
3935 threadfunc(tmp[1]);
3936 free(tmp);
3937
3938 /* Free colors */
3939 _dw_deinit_thread();
3940 }
3941
3942 /*
3943 * Allocates a shared memory region with a name.
3944 * Parameters:
3945 * handle: A pointer to receive a SHM identifier.
3946 * dest: A pointer to a pointer to receive the memory address.
3947 * size: Size in bytes of the shared memory region to allocate.
3948 * name: A string pointer to a unique memory name.
3949 */
3950 HSHM API dw_named_memory_new(void **dest, int size, const char *name)
3951 {
3952 char namebuf[1025];
3953 struct _dw_unix_shm *handle = (struct _dw_unix_shm *)malloc(sizeof(struct _dw_unix_shm));
3954
3955 mkdir("/tmp/.dw", S_IWGRP|S_IWOTH);
3956 snprintf(namebuf, 1024, "/tmp/.dw/%s", name);
3957
3958 if((handle->fd = open(namebuf, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0)
3959 {
3960 free(handle);
3961 return NULL;
3962 }
3963
3964 if(ftruncate(handle->fd, size))
3965 {
3966 close(handle->fd);
3967 free(handle);
3968 return NULL;
3969 }
3970
3971 /* attach the shared memory segment to our process's address space. */
3972 *dest = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, handle->fd, 0);
3973
3974 if(*dest == MAP_FAILED)
3975 {
3976 close(handle->fd);
3977 *dest = NULL;
3978 free(handle);
3979 return NULL;
3980 }
3981
3982 handle->size = size;
3983 handle->sid = getsid(0);
3984 handle->path = strdup(namebuf);
3985
3986 return handle;
3987 }
3988
3989 /*
3990 * Aquires shared memory region with a name.
3991 * Parameters:
3992 * dest: A pointer to a pointer to receive the memory address.
3993 * size: Size in bytes of the shared memory region to requested.
3994 * name: A string pointer to a unique memory name.
3995 */
3996 HSHM API dw_named_memory_get(void **dest, int size, const char *name)
3997 {
3998 char namebuf[1025];
3999 struct _dw_unix_shm *handle = (struct _dw_unix_shm *)malloc(sizeof(struct _dw_unix_shm));
4000
4001 mkdir("/tmp/.dw", S_IWGRP|S_IWOTH);
4002 snprintf(namebuf, 1024, "/tmp/.dw/%s", name);
4003
4004 if((handle->fd = open(namebuf, O_RDWR)) < 0)
4005 {
4006 free(handle);
4007 return NULL;
4008 }
4009
4010 /* attach the shared memory segment to our process's address space. */
4011 *dest = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, handle->fd, 0);
4012
4013 if(*dest == MAP_FAILED)
4014 {
4015 close(handle->fd);
4016 *dest = NULL;
4017 free(handle);
4018 return NULL;
4019 }
4020
4021 handle->size = size;
4022 handle->sid = -1;
4023 handle->path = NULL;
4024
4025 return handle;
4026 }
4027
4028 /*
4029 * Frees a shared memory region previously allocated.
4030 * Parameters:
4031 * handle: Handle obtained from DB_named_memory_allocate.
4032 * ptr: The memory address aquired with DB_named_memory_allocate.
4033 */
4034 int API dw_named_memory_free(HSHM handle, void *ptr)
4035 {
4036 struct _dw_unix_shm *h = (struct _dw_unix_shm *)handle;
4037 int rc = munmap(ptr, h->size);
4038
4039 close(h->fd);
4040 if(h->path)
4041 {
4042 /* Only remove the actual file if we are the
4043 * creator of the file.
4044 */
4045 if(h->sid != -1 && h->sid == getsid(0))
4046 remove(h->path);
4047 free(h->path);
4048 }
4049 return rc;
4050 }
4051 /*
4052 * Creates a new thread with a starting point of func.
4053 * Parameters:
4054 * func: Function which will be run in the new thread.
4055 * data: Parameter(s) passed to the function.
4056 * stack: Stack size of new thread (OS/2 and Windows only).
4057 */
4058 DWTID API dw_thread_new(void *func, void *data, int stack)
4059 {
4060 DWTID dwthread;
4061 void **tmp = (void **)malloc(sizeof(void *) * 2);
4062 int rc;
4063
4064 tmp[0] = func;
4065 tmp[1] = data;
4066
4067 rc = pthread_create(&dwthread, NULL, (void *(*)(void *))_dwthreadstart, (void *)tmp);
4068 if(rc == 0)
4069 return dwthread;
4070 return (DWTID)DW_ERROR_UNKNOWN;
4071 }
4072
4073 /*
4074 * Ends execution of current thread immediately.
4075 */
4076 void API dw_thread_end(void)
4077 {
4078 pthread_exit(NULL);
4079 }
4080
4081 /*
4082 * Returns the current thread's ID.
4083 */
4084 DWTID API dw_thread_id(void)
4085 {
4086 return (DWTID)pthread_self();
3443 } 4087 }
3444 4088
3445 /* 4089 /*
3446 * Initializes the Dynamic Windows engine. 4090 * Initializes the Dynamic Windows engine.
3447 * Parameters: 4091 * Parameters:
3452 * Returns: 4096 * Returns:
3453 * DW_ERROR_NONE (0) on success. 4097 * DW_ERROR_NONE (0) on success.
3454 */ 4098 */
3455 int API dw_init(int newthread, int argc, char *argv[]) 4099 int API dw_init(int newthread, int argc, char *argv[])
3456 { 4100 {
3457 return DW_ERROR_NONE; 4101 return DW_ERROR_NONE;
3458 }
3459
3460 /*
3461 * Allocates a shared memory region with a name.
3462 * Parameters:
3463 * dest: A pointer to a pointer to receive the memory address.
3464 * size: Size in bytes of the shared memory region to allocate.
3465 * name: A string pointer to a unique memory name.
3466 * Returns:
3467 * Handle to shared memory or NULL on error.
3468 */
3469 HSHM API dw_named_memory_new(void **dest, int size, const char *name)
3470 {
3471 return NULL;
3472 }
3473
3474 /*
3475 * Aquires shared memory region with a name.
3476 * Parameters:
3477 * dest: A pointer to a pointer to receive the memory address.
3478 * size: Size in bytes of the shared memory region to requested.
3479 * name: A string pointer to a unique memory name.
3480 * Returns:
3481 * Handle to shared memory or NULL on error.
3482 */
3483 HSHM API dw_named_memory_get(void **dest, int size, const char *name)
3484 {
3485 return NULL;
3486 }
3487
3488 /*
3489 * Frees a shared memory region previously allocated.
3490 * Parameters:
3491 * handle: Handle obtained from dw_named_memory_new().
3492 * ptr: The memory address aquired with dw_named_memory_new().
3493 * Returns:
3494 * DW_ERROR_NONE (0) on success or DW_ERROR_UNKNOWN (-1) on error.
3495 */
3496 int API dw_named_memory_free(HSHM handle, void *ptr)
3497 {
3498 int rc = DW_ERROR_UNKNOWN;
3499
3500 return rc;
3501 }
3502
3503 /*
3504 * Generally an internal function called from a newly created
3505 * thread to setup the Dynamic Windows environment for the thread.
3506 * However it is exported so language bindings can call it when
3507 * they create threads that require access to Dynamic Windows.
3508 */
3509 void API _dw_init_thread(void)
3510 {
3511 }
3512
3513 /*
3514 * Generally an internal function called from a terminating
3515 * thread to cleanup the Dynamic Windows environment for the thread.
3516 * However it is exported so language bindings can call it when
3517 * they exit threads that require access to Dynamic Windows.
3518 */
3519 void API _dw_deinit_thread(void)
3520 {
3521 }
3522
3523 /*
3524 * Creates a new thread with a starting point of func.
3525 * Parameters:
3526 * func: Function which will be run in the new thread.
3527 * data: Parameter(s) passed to the function.
3528 * stack: Stack size of new thread (OS/2 and Windows only).
3529 * Returns:
3530 * Thread ID on success or DW_ERROR_UNKNOWN (-1) on error.
3531 */
3532 DWTID API dw_thread_new(void *func, void *data, int stack)
3533 {
3534 return (DWTID)DW_ERROR_UNKNOWN;
3535 }
3536
3537 /*
3538 * Ends execution of current thread immediately.
3539 */
3540 void API dw_thread_end(void)
3541 {
3542 }
3543
3544 /*
3545 * Returns the current thread's ID.
3546 */
3547 DWTID API dw_thread_id(void)
3548 {
3549 return (DWTID)0;
3550 } 4102 }
3551 4103
3552 /* 4104 /*
3553 * Cleanly terminates a DW session, should be signal handler safe. 4105 * Cleanly terminates a DW session, should be signal handler safe.
3554 */ 4106 */
3661 * Wide string that needs to be freed with dw_free() 4213 * Wide string that needs to be freed with dw_free()
3662 * or NULL on failure. 4214 * or NULL on failure.
3663 */ 4215 */
3664 wchar_t * API dw_utf8_to_wchar(const char *utf8string) 4216 wchar_t * API dw_utf8_to_wchar(const char *utf8string)
3665 { 4217 {
3666 return NULL; 4218 size_t buflen = strlen(utf8string) + 1;
4219 wchar_t *temp = (wchar_t *)malloc(buflen * sizeof(wchar_t));
4220 if(temp)
4221 mbstowcs(temp, utf8string, buflen);
4222 return temp;
3667 } 4223 }
3668 4224
3669 /* 4225 /*
3670 * Converts a wide string into a UTF-8 encoded string. 4226 * Converts a wide string into a UTF-8 encoded string.
3671 * Parameters: 4227 * Parameters:
3674 * UTF-8 encoded string that needs to be freed with dw_free() 4230 * UTF-8 encoded string that needs to be freed with dw_free()
3675 * or NULL on failure. 4231 * or NULL on failure.
3676 */ 4232 */
3677 char * API dw_wchar_to_utf8(const wchar_t *wstring) 4233 char * API dw_wchar_to_utf8(const wchar_t *wstring)
3678 { 4234 {
3679 return NULL; 4235 size_t bufflen = 8 * wcslen(wstring) + 1;
4236 char *temp = (char *)malloc(bufflen);
4237 if(temp)
4238 wcstombs(temp, wstring, bufflen);
4239 return temp;
3680 } 4240 }
3681 4241
3682 /* 4242 /*
3683 * Gets the state of the requested library feature. 4243 * Gets the state of the requested library feature.
3684 * Parameters: 4244 * Parameters: