00001
00017
00018
00019
00020
00021 #include "sic_comm.h"
00022
00023 #ifndef WIN32
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <errno.h>
00027 #include <time.h>
00028 #include <string.h>
00029 #include <unistd.h>
00030 #include <sys/wait.h>
00031 #include <sys/stat.h>
00032 #endif
00033
00034 #ifdef GAG_SYSV
00035 #include <sys/shm.h>
00036 #include <sys/sem.h>
00037 #elif defined(WIN32)
00038 #else
00039 #include <fcntl.h>
00040 #include <sys/mman.h>
00041 #include <semaphore.h>
00042 #endif
00043 #ifdef cygwin
00044 #include <limits.h>
00045 #endif
00046
00047 #include "ctrlc.h"
00048 #include "sic_error.h"
00049 #include "gag_trace.h"
00050
00051
00052
00053
00054
00055 #define SIC_DEBUG_COMM
00056 #if defined(darwin) || defined(cygwin) || defined(linux)
00057 #define SIC_USE_SEM_OPEN
00058 #endif
00059
00060 #ifndef SIGCLD
00061 #define SIGCLD SIGCHLD
00062 #endif
00063
00064 #ifdef SIC_DEBUG_COMM
00065 #define SIC_ASSERT( message, condition) \
00066 { if (!(condition)) fprintf( stderr, "SIC_ASSERT: %s\n", message); }
00067 #else
00068 #define SIC_ASSERT( message, condition)
00069 #endif
00070
00071 #define MAX_ARGC 32
00072 #define MAX_ARGV 256
00073
00074 #define SIC_MAX_WIDGET_ON_BOARD 1000
00075 #define SIC_MAX_SHM_NAME 32
00076 #define SIC_MAX_SEM_NAME_FOR_PORTABILITY 14
00077 #define SIC_MAX_HANDLERS 32
00078
00079
00080 #define SIC_MODIFIED_VARIABLE_EVENT 1
00081 #define SIC_REDRAW_PROMPT_EVENT 2
00082
00083 #if defined(GAG_SYSV)
00084 typedef struct {
00085 int sem_id;
00086 } sic_sem_t;
00087 #define SIC_SEM_ID(x) ((x)->sem_id)
00088 #elif defined(WIN32)
00089 typedef struct {
00090 HANDLE sem_id;
00091 } sic_sem_t;
00092 #define SIC_SEM_ID(x) ((x)->sem_id)
00093 #else
00094 typedef struct {
00095 #ifdef SIC_USE_SEM_OPEN
00096 sem_t *sem_id;
00097 #define SIC_SEM_ID(x) ((x)->sem_id)
00098 #else
00099 sem_t sem_id;
00100 #define SIC_SEM_ID(x) (&(x)->sem_id)
00101 #endif
00102 char name[SIC_MAX_SEM_NAME_FOR_PORTABILITY];
00103 } sic_sem_t;
00104
00105 #endif
00106
00107 typedef struct {
00108 task_t task;
00109 int event_id;
00110 void (*listener)();
00111 int sig_num;
00112 } sic_listener_handler_t;
00113
00114 typedef struct {
00115 task_t master_task;
00116 task_t keyboard_task;
00117 int trace_fd;
00118 sic_sem_t comm_board_access;
00119 sic_sem_t draw_prompt;
00120 sic_sem_t write_command;
00121 sic_sem_t read_command;
00122 sic_sem_t listener_acquit;
00123 sic_sem_t widget_board_access;
00124 sic_sem_t widget_created;
00125 int widget_board_id;
00126 command_line_t command_line;
00127 char pushed_command_text[MAXBUF];
00128 sic_command_from_t from;
00129 int listener_count;
00130 sic_listener_handler_t listeners[SIC_MAX_HANDLERS];
00131 int event_id;
00132 } sic_comm_board_t;
00133
00134 typedef struct {
00135 char window_title[TITLELENGTH];
00136 char help_filename[HLPFILELNGTH];
00137 char returned_command[COMMANDLENGTH];
00138 int returned_code;
00139 sic_widget_def_t modified_widget;
00140 int widget_count;
00141 sic_widget_def_t widgets[SIC_MAX_WIDGET_ON_BOARD];
00142 } sic_widget_board_t;
00143
00144
00145 static int s_comm_board_id = -1;
00146 static char s_comm_shm_name[SIC_MAX_SHM_NAME];
00147 static sic_comm_board_t *s_comm_board = NULL;
00148 static sic_comm_board_t *s_sem_comm_board = NULL;
00149
00150
00151 static char s_widget_shm_name[SIC_MAX_SHM_NAME];
00152 static sic_widget_board_t *s_widget_board = NULL;
00153
00154
00155 static int s_ctrlc_handled = 0;
00156
00157
00158
00159
00160
00161 #ifdef cygwin
00162
00163 int shm_open( const char *name, int oflag, mode_t mode)
00164 {
00165 static int s_first_call = 1;
00166 int fd;
00167 char shm_name[PATH_MAX + 20] = "/dev/shm/";
00168
00169 if (s_first_call) {
00170 struct stat tmp;
00171 if (stat( "/dev", &tmp))
00172 if (mkdir( "/dev", 0777))
00173 sic_perror( "mkdir");
00174 if (stat( shm_name, &tmp))
00175 if (mkdir( shm_name, 0777))
00176 sic_perror( "mkdir");
00177 s_first_call = 0;
00178 }
00179
00180
00181 if (*name == '/')
00182 ++name;
00183
00184
00185
00186 strlcpy( shm_name + 9, name, PATH_MAX + 10);
00187
00188 fd = open( shm_name, oflag, mode);
00189
00190 if (fd != -1) {
00191
00192 int flags = fcntl( fd, F_GETFD, 0);
00193
00194 if (flags >= 0) {
00195 flags |= FD_CLOEXEC;
00196 flags = fcntl( fd, F_SETFD, flags);
00197 }
00198
00199
00200 if (flags == -1) {
00201 sic_perror( "fcntl");
00202 close( fd);
00203 fd = -1;
00204 }
00205 } else
00206 sic_perror( "open");
00207
00208 return fd;
00209 }
00210
00211 int shm_unlink( const char *name)
00212 {
00213 int rc;
00214 char shm_name[PATH_MAX + 20] = "/dev/shm/";
00215
00216
00217 if (*name == '/')
00218 ++name;
00219
00220
00221
00222 strlcpy( shm_name + 9, name, PATH_MAX + 10);
00223
00224 rc = unlink( shm_name);
00225
00226 return rc;
00227 }
00228
00229 #endif
00230
00231 static int sic_shm_create( const char* name, int size)
00232 {
00233 #ifndef WIN32
00234 int shm_id;
00235
00236 #ifdef GAG_SYSV
00237 shm_id = shmget( IPC_PRIVATE, size, 0600);
00238
00239 if (shm_id == -1) {
00240 sic_perror( "shmget");
00241 }
00242
00243 #else
00244 shm_id = shm_open( name, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG);
00245 if (shm_id == -1) {
00246 sic_perror( "shm_open");
00247 }
00248
00249 #ifndef DONT_SET_CLOSE_ON_EXEC_TO_ZERO
00250 if (fcntl( shm_id, F_SETFD, 0) == -1) {
00251 sic_perror( "fcntl");
00252 }
00253 #endif
00254
00255 if (ftruncate( shm_id, size) == -1) {
00256 sic_perror( "ftruncate");
00257 }
00258 #endif
00259
00260 return shm_id;
00261 #else
00262 return 0;
00263 #endif
00264 }
00265
00266 static void sic_shm_destroy( const char* name, int shm_id)
00267 {
00268 #ifndef WIN32
00269 #ifdef GAG_SYSV
00270 if (shmctl( shm_id, IPC_RMID, NULL) == -1) {
00271 sic_perror( "shmctl");
00272 }
00273
00274 #else
00275 if (close( shm_id) == -1) {
00276 sic_perror( "close");
00277 }
00278
00279 if (shm_unlink( name) == -1) {
00280 sic_perror( "shm_unlink");
00281 }
00282 #endif
00283 #endif
00284 }
00285
00286 static void* sic_shm_attach( int shm_id, int size)
00287 {
00288 void* addr = NULL;
00289
00290 #ifndef WIN32
00291 #ifdef GAG_SYSV
00292 addr = shmat( shm_id, (char *)NULL, 0);
00293 if ((long)addr == -1) {
00294 sic_perror( "shmat");
00295 }
00296
00297 #else
00298 addr = mmap( NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_id, 0);
00299 if (addr == MAP_FAILED) {
00300 sic_perror( "mmap");
00301 }
00302 #endif
00303 #endif
00304
00305 return addr;
00306 }
00307
00308 static void sic_shm_detach( void *addr, int size)
00309 {
00310 #ifndef WIN32
00311 #ifdef GAG_SYSV
00312 if (shmdt( addr) == -1) {
00313 sic_perror( "shmdt");
00314 }
00315
00316 #else
00317 if (munmap( addr, size) == -1) {
00318 sic_perror( "munmap");
00319 }
00320 #endif
00321 #endif
00322 }
00323
00324 static void sic_sem_open( sic_sem_t *sem)
00325 {
00326 #ifndef WIN32
00327 #ifndef GAG_SYSV
00328 #ifdef SIC_USE_SEM_OPEN
00329 static char sem_name[SIC_MAX_SEM_NAME_FOR_PORTABILITY];
00330 static int count = 0;
00331
00332 #ifdef SIC_DEBUG_COMM
00333 if (s_comm_board == NULL)
00334 return;
00335 #endif
00336
00337 sprintf( sem_name, "/SIC_%d_%d", sic_get_master_task_id( ), ++count);
00338 sem_t *ret = sem_open( sem_name, 0);
00339 if (ret == (sem_t *)SEM_FAILED) {
00340 sic_perror( "sem_open");
00341 }
00342 SIC_SEM_ID(sem) = ret;
00343 #endif
00344 #endif
00345 #endif
00346 }
00347
00348 static void sic_sem_create( sic_sem_t *sem, unsigned int initial_value)
00349 {
00350 #if defined(WIN32)
00351 SIC_SEM_ID(sem) = CreateSemaphore( NULL, initial_value, 1, NULL);
00352 if (SIC_SEM_ID(sem) == NULL) {
00353 sic_perror( "CreateSemaphore");
00354 }
00355 #elif defined(GAG_SYSV)
00356 SIC_SEM_ID(sem) = semget( IPC_PRIVATE, 1, S_IRUSR | S_IWUSR);
00357 if (SIC_SEM_ID(sem) == -1) {
00358 sic_perror( "semget");
00359 }
00360
00361 if (semctl( SIC_SEM_ID(sem), 0, SETVAL, initial_value) == -1) {
00362 sic_perror( "semctl");
00363 }
00364
00365 #else
00366 #ifdef SIC_USE_SEM_OPEN
00367 static char sem_name[SIC_MAX_SEM_NAME_FOR_PORTABILITY];
00368 static int count = 0;
00369
00370 sprintf( sem_name, "/SIC_%d_%d", sic_get_master_task_id( ), ++count);
00371 sem_t *ret = sem_open( sem_name, O_CREAT, S_IRUSR | S_IWUSR, initial_value);
00372 if (ret == (sem_t *)SEM_FAILED) {
00373 sic_perror( "sem_open");
00374 }
00375 SIC_SEM_ID(sem) = ret;
00376 strncpy( sem->name, sem_name, SIC_MAX_SEM_NAME_FOR_PORTABILITY);
00377 #else
00378 if (sem_init( SIC_SEM_ID(sem), 1, initial_value) == -1) {
00379 sic_perror( "sem_init");
00380 }
00381 #endif
00382 #endif
00383 }
00384
00385 static void sic_sem_close( sic_sem_t *sem)
00386 {
00387 #ifdef SIC_DEBUG_COMM
00388 if (s_comm_board == NULL)
00389 return;
00390 #endif
00391
00392 #if defined(WIN32)
00393 if (CloseHandle( SIC_SEM_ID(sem)) == FALSE) {
00394 sic_perror( "CloseHandle");
00395 }
00396 #elif defined(SIC_USE_SEM_OPEN)
00397 #ifndef cygwin
00398 if (sem_close( SIC_SEM_ID(sem)) == -1) {
00399 sic_perror( "sem_close");
00400 }
00401 #endif
00402 #endif
00403 }
00404
00405 static void sic_sem_destroy( sic_sem_t *sem)
00406 {
00407 #ifdef SIC_DEBUG_COMM
00408 if (s_comm_board == NULL)
00409 return;
00410 #endif
00411
00412 sic_sem_close( sem);
00413 #if defined(WIN32)
00414 #elif defined(GAG_SYSV)
00415 if (semctl( SIC_SEM_ID(sem), 0, IPC_RMID) == -1) {
00416 sic_perror( "semctl");
00417 }
00418 #elif defined(SIC_USE_SEM_OPEN)
00419 #ifndef cygwin
00420 if (sem_unlink( sem->name) == -1) {
00421 sic_perror( "sem_unlink");
00422 }
00423 #else
00424 if (sem_close( SIC_SEM_ID(sem)) == -1) {
00425 sic_perror( "sem_close");
00426 }
00427 #endif
00428 #else
00429 if (sem_destroy( SIC_SEM_ID(sem)) == -1) {
00430 sic_perror( "sem_destroy");
00431 }
00432 #endif
00433 }
00434
00435 static void sic_sem_post( sic_sem_t *sem)
00436 {
00437 #if defined(GAG_SYSV)
00438 struct sembuf sops;
00439 #endif
00440
00441 #ifdef SIC_DEBUG_COMM
00442 if (s_comm_board == NULL)
00443 return;
00444 #endif
00445
00446 #if defined(WIN32)
00447 if (!ReleaseSemaphore( SIC_SEM_ID(sem), 1, NULL)) {
00448 sic_perror( "ReleaseSemaphore");
00449 }
00450 #elif defined(GAG_SYSV)
00451 sops.sem_num = 0;
00452 sops.sem_op = 1;
00453 sops.sem_flg = 0;
00454
00455 if (semop( SIC_SEM_ID(sem), &sops, 1) == -1) {
00456 sic_perror( "semop");
00457 }
00458
00459 #else
00460 if (sem_post( SIC_SEM_ID(sem)) == -1) {
00461 sic_perror( "sem_post");
00462 }
00463 #endif
00464 }
00465
00466 static void sic_sem_wait( sic_sem_t *sem)
00467 {
00468 #if defined(GAG_SYSV)
00469 struct sembuf sops;
00470 #endif
00471
00472 #ifdef SIC_DEBUG_COMM
00473 if (s_comm_board == NULL)
00474 return;
00475 #endif
00476
00477 #if defined(WIN32)
00478 if (WaitForSingleObject( SIC_SEM_ID(sem), INFINITE) != WAIT_OBJECT_0) {
00479 sic_perror( "WaitForSingleObject");
00480 }
00481 #elif defined(GAG_SYSV)
00482 sops.sem_num = 0;
00483 sops.sem_op = -1;
00484 sops.sem_flg = 0;
00485
00486 while (semop( SIC_SEM_ID(sem), &sops, 1) == -1) {
00487 if (errno == EINTR)
00488 errno = 0;
00489 else
00490 sic_perror( "semop");
00491 }
00492 #else
00493 while (sem_wait( SIC_SEM_ID(sem)) == -1) {
00494 if (errno == EINTR)
00495 errno = 0;
00496 else
00497 sic_perror( "sem_wait");
00498 }
00499 #endif
00500 }
00501
00502 static int sic_sem_timed_wait( sic_sem_t *sem, int timeout)
00503 {
00504 int ret = 0;
00505
00506 #ifdef SIC_DEBUG_COMM
00507 if (s_comm_board == NULL)
00508 return 0;
00509 #endif
00510
00511 if (timeout == -1) {
00512 sic_sem_wait( sem);
00513 return 0;
00514 } else {
00515 #if defined(WIN32)
00516 DWORD wait = WaitForSingleObject( SIC_SEM_ID(sem), timeout);
00517 if (wait != WAIT_OBJECT_0) {
00518 if (wait == WAIT_TIMEOUT)
00519 ret = -1;
00520 else
00521 sic_perror( "WaitForSingleObject");
00522 }
00523 #elif defined(GAG_SYSV) || defined(darwin)
00524 sic_sem_wait( sem);
00525 #else
00526 struct timespec t;
00527
00528 clock_gettime( CLOCK_REALTIME, &t);
00529
00530
00531 time_t nb_sec = timeout / 1000;
00532
00533 long nb_nsec = (timeout - nb_sec * 1000) * 1000000L;
00534 if (nb_nsec + t.tv_nsec > 1000000000L) {
00535 nb_sec++;
00536 nb_nsec -= 1000000000L;
00537 }
00538 t.tv_sec += nb_sec;
00539 t.tv_nsec += nb_nsec;
00540
00541 ret = sem_timedwait( SIC_SEM_ID(sem), &t);
00542 if (ret == -1) {
00543 if (errno == EINTR || errno == ETIMEDOUT)
00544 errno = 0;
00545 else
00546 sic_perror( "sem_timedwait");
00547 }
00548 #endif
00549 }
00550 return ret;
00551 }
00552
00553 static void sic_on_modified_variable( sic_listener_handler_t *h)
00554 {
00555 gag_trace( "<trace> sic_on_modified_variable");
00556
00557 (*(sic_modified_variable_listener_t)h->listener)( &s_widget_board->modified_widget);
00558 }
00559
00560 static void sic_on_redraw_prompt( sic_listener_handler_t *h)
00561 {
00562 gag_trace( "<trace> sic_on_redraw_prompt");
00563 (*(sic_redraw_prompt_listener_t)h->listener)( &s_comm_board->command_line);
00564 }
00565
00566 static void sic_on_event( sic_listener_handler_t *h)
00567 {
00568 switch (h->event_id) {
00569 case SIC_MODIFIED_VARIABLE_EVENT:
00570 sic_on_modified_variable( h);
00571 break;
00572 case SIC_REDRAW_PROMPT_EVENT:
00573 sic_on_redraw_prompt( h);
00574 break;
00575 }
00576 #ifndef WIN32
00577 sic_sem_post( &s_sem_comm_board->listener_acquit);
00578 #endif
00579 }
00580
00581 static void sic_event_handler( int sig_num)
00582 {
00583 int i;
00584 int event_id = s_comm_board->event_id;
00585
00586 #ifndef WIN32
00587 signal( sig_num, sic_event_handler);
00588 #endif
00589 for (i = 0; i < s_comm_board->listener_count; i++) {
00590 sic_listener_handler_t *h = &s_comm_board->listeners[i];
00591 if (h->event_id == event_id) {
00592 sic_on_event( h);
00593 }
00594 }
00595 }
00596
00597 static void sic_record_listener( sic_listener_handler_t *widget_handler)
00598 {
00599 #ifdef SIC_DEBUG_COMM
00600 if (s_comm_board == NULL)
00601 return;
00602 #endif
00603
00604 sic_sem_wait( &s_sem_comm_board->comm_board_access);
00605
00606 s_comm_board->listeners[s_comm_board->listener_count++] = *widget_handler;
00607 #ifndef WIN32
00608 signal( widget_handler->sig_num, sic_event_handler);
00609 #endif
00610
00611 sic_sem_post( &s_sem_comm_board->comm_board_access);
00612 }
00613
00614 static void sic_trigger_listener( sic_listener_handler_t *h)
00615 {
00616 #ifndef WIN32
00617 if (kill( h->task, h->sig_num) == 0)
00618 sic_sem_timed_wait( &s_sem_comm_board->listener_acquit, 1000);
00619 #else
00620 sic_on_event( h);
00621 #endif
00622 }
00623
00624 static void sic_trigger_listeners( int event_id)
00625 {
00626 int i;
00627
00628 sic_sem_wait( &s_sem_comm_board->comm_board_access);
00629
00630 s_comm_board->event_id = event_id;
00631
00632 for (i = 0; i < s_comm_board->listener_count; i++) {
00633 sic_listener_handler_t *h = &s_comm_board->listeners[i];
00634 if (h->event_id == event_id)
00635 sic_trigger_listener( h);
00636 }
00637
00638 sic_sem_post( &s_sem_comm_board->comm_board_access);
00639 }
00640
00641 static void sic_purge_listeners( task_t task)
00642 {
00643 int i;
00644 int j;
00645
00646 sic_sem_wait( &s_sem_comm_board->comm_board_access);
00647
00648 j = 0;
00649 for (i = 0; i < s_comm_board->listener_count; i++) {
00650 sic_listener_handler_t *h = &s_comm_board->listeners[i];
00651 if (h->task != task) {
00652 if (j != i)
00653 s_comm_board->listeners[j] = *h;
00654 j++;
00655 }
00656 }
00657 s_comm_board->listener_count = j;
00658
00659 sic_sem_post( &s_sem_comm_board->comm_board_access);
00660 }
00661
00662 static int sic_is_master( )
00663 {
00664 return s_comm_board_id != -1;
00665 }
00666
00667 static void sic_kill_all_child_processes( )
00668 {
00669 #ifndef WIN32
00670 signal( SIGCLD, SIG_IGN);
00671 signal( SIGTERM, SIG_IGN);
00672 kill( 0, SIGTERM);
00673 wait( 0);
00674 #endif
00675 }
00676
00677 static void sic_signal_handler( int sig_num)
00678 {
00679 gag_trace( "<trace: signal> sic_signal_handler on %d", sig_num);
00680 sic_do_exit( 1);
00681 }
00682
00683 static void sic_init_handlers( )
00684 {
00685 atexit( sic_on_exit);
00686 #ifndef WIN32
00687 if (!s_ctrlc_handled)
00688 signal( SIGINT, SIG_IGN);
00689 signal( SIGTTOU, SIG_IGN);
00690
00691 signal( SIGHUP, sic_signal_handler);
00692 signal( SIGQUIT, sic_signal_handler);
00693 signal( SIGILL, sic_signal_handler);
00694 signal( SIGABRT, sic_signal_handler);
00695 signal( SIGBUS, sic_signal_handler);
00696 signal( SIGFPE, sic_signal_handler);
00697 signal( SIGSEGV, sic_signal_handler);
00698 signal( SIGPIPE, sic_signal_handler);
00699 signal( SIGTERM, sic_signal_handler);
00700 signal( SIGSTOP, sic_signal_handler);
00701 signal( SIGSYS, sic_signal_handler);
00702 #if defined(SIGIO)
00703 signal( SIGIO, sic_signal_handler);
00704 #elif defined(SIGPOLL)
00705 signal( SIGPOLL, sic_signal_handler);
00706 #endif
00707 #endif
00708 }
00709
00718 static int sic_raw_post_command_from( const command_line_t *command_line, int timeout, sic_command_from_t from)
00719 {
00720 int ret;
00721
00722 #ifdef SIC_DEBUG_COMM
00723 if (s_comm_board == NULL)
00724 return 0;
00725 #endif
00726
00727 gag_trace( "<trace: enter> sic_post_command");
00728 ret = sic_sem_timed_wait( &s_sem_comm_board->write_command, timeout);
00729 if (ret == 0) {
00730
00731 strncpy( (char*)command_line->prompt, s_comm_board->command_line.prompt, PROMPT);
00732 s_comm_board->command_line = *command_line;
00733 s_comm_board->from = from;
00734 gag_trace( "<command: send> \"%s%s\"", command_line->prompt, command_line->line);
00735 sic_sem_post( &s_sem_comm_board->read_command);
00736 }
00737 gag_trace( "<trace: leave> sic_post_command");
00738 return ret;
00739 }
00740
00741 static void sic_build_command_line( const char* text, command_line_t *command_line)
00742 {
00743 strncpy( command_line->line, text, MAXBUF);
00744 command_line->nc = (int)strlen( text);
00745 command_line->prompt[0] = '\0';
00746 command_line->code = 0;
00747 }
00748
00749
00750
00751
00752
00757 void sic_create_comm_board( )
00758 {
00759 char *trace = getenv( "SIC_COMM_TRACE");
00760 if (trace != NULL) {
00761 gag_trace_open( trace);
00762 }
00763
00764 gag_trace( "<trace: enter> sic_create_comm_board");
00765 if (s_comm_board_id == -1) {
00766 sprintf( s_comm_shm_name, "/SIC_%d_C", sic_get_current_task_id( ));
00767 s_comm_board_id = sic_shm_create( s_comm_shm_name, sizeof( sic_comm_board_t));
00768 sic_open_comm_board( s_comm_board_id);
00769 s_comm_board->master_task = sic_get_current_task( );
00770 s_comm_board->keyboard_task = SIC_TASK_NULL;
00771 if (gag_trace_get_file_pointer( ) != NULL)
00772 s_comm_board->trace_fd = fileno( gag_trace_get_file_pointer( ));
00773 else
00774 s_comm_board->trace_fd = -1;
00775 sic_sem_create( &s_sem_comm_board->comm_board_access, 1);
00776 sic_sem_create( &s_sem_comm_board->draw_prompt, 0);
00777 sic_sem_create( &s_sem_comm_board->write_command, 0);
00778 sic_sem_create( &s_sem_comm_board->read_command, 0);
00779 sic_sem_create( &s_sem_comm_board->widget_board_access, 1);
00780 sic_sem_create( &s_sem_comm_board->widget_created, 0);
00781 sic_sem_create( &s_sem_comm_board->listener_acquit, 0);
00782 s_comm_board->widget_board_id = -1;
00783 sic_build_command_line( "", &s_comm_board->command_line);
00784 s_comm_board->pushed_command_text[0] = '\0';
00785 s_comm_board->from = -1;
00786 s_comm_board->listener_count = 0;
00787 s_comm_board->event_id = -1;
00788 }
00789 gag_trace( "<trace: leave> sic_create_comm_board");
00790 }
00791
00795 void sic_destroy_comm_board( )
00796 {
00797 gag_trace( "<trace: enter> sic_destroy_comm_board");
00798
00799 SIC_ASSERT( "sic_destroy_comm_board called from child process", sic_is_master( ));
00800
00801 sic_kill_all_child_processes( );
00802 if (s_sem_comm_board != NULL) {
00803 sic_sem_destroy( &s_sem_comm_board->comm_board_access);
00804 sic_sem_destroy( &s_sem_comm_board->draw_prompt);
00805 sic_sem_destroy( &s_sem_comm_board->write_command);
00806 sic_sem_destroy( &s_sem_comm_board->read_command);
00807 sic_sem_destroy( &s_sem_comm_board->widget_board_access);
00808 sic_sem_destroy( &s_sem_comm_board->widget_created);
00809 sic_sem_destroy( &s_sem_comm_board->listener_acquit);
00810 s_sem_comm_board = NULL;
00811 }
00812
00813 sic_close_comm_board( );
00814
00815 if (s_comm_board_id >= 0) {
00816 sic_shm_destroy( s_comm_shm_name, s_comm_board_id);
00817
00818 s_comm_board_id = -1;
00819 }
00820
00821 gag_trace( "<trace: leave> sic_destroy_comm_board");
00822 }
00823
00824 #ifndef WIN32
00825
00826
00827
00828 static pid_t sic_fork( )
00829 {
00830 pid_t pid;
00831
00832 gag_trace( "<trace: fork>");
00833
00834
00835
00836 fflush( NULL);
00837
00838 pid = fork( );
00839 if (pid < 0) {
00840 sic_perror( "fork");
00841 } else if (pid) {
00842 gag_trace( "<trace: fork> process %d created", pid);
00843 } else {
00844 gag_trace( "<trace: fork> child starting");
00845 }
00846 return pid;
00847 }
00848 #endif
00849
00853 char **sic_get_static_argv( )
00854 {
00855 static char *s_argv[MAX_ARGC];
00856 static char s_argv_buf[MAX_ARGC][MAX_ARGV];
00857 int i;
00858
00859
00860 for (i = 0; i < MAX_ARGC; i++)
00861 s_argv[i] = s_argv_buf[i];
00862
00863 return s_argv;
00864 }
00865
00873 int sic_execvp( char *argv[])
00874 {
00875 #ifndef WIN32
00876 #ifdef SIC_DEBUG_COMM
00877 char gdb_cmd_file[MAX_ARGV];
00878 FILE *fp;
00879 int i;
00880 static char *exec_argv[MAX_ARGC];
00881 static char exec_argv_buf[MAX_ARGC][MAX_ARGV];
00882 #endif
00883 char *app_name = argv[0];
00884
00885 gag_trace( "<trace: exec> %s", app_name);
00886
00887 #ifdef SIC_DEBUG_COMM
00888 if (getenv( "SIC_DEBUG_GDB") == NULL)
00889 #endif
00890
00891 return execvp( argv[0], argv);
00892
00893 #ifdef SIC_DEBUG_COMM
00894
00895
00896 for (i = 0; i < MAX_ARGC; i++)
00897 exec_argv[i] = exec_argv_buf[i];
00898
00899
00900 sprintf( gdb_cmd_file, ".gdb_%s", app_name);
00901 fp = fopen( gdb_cmd_file, "w");
00902 fprintf( fp, "set args");
00903 for (i = 1; argv[i] != NULL; i++) {
00904 fprintf( fp, " \"%s\"", argv[i]);
00905 }
00906 fprintf( fp, "\n");
00907 fclose( fp);
00908
00909
00910 i = 0;
00911 sprintf( exec_argv[i++], "xterm");
00912 sprintf( exec_argv[i++], "-T");
00913 sprintf( exec_argv[i++], app_name);
00914 sprintf( exec_argv[i++], "-e");
00915 sprintf( exec_argv[i++], "gdb");
00916 sprintf( exec_argv[i++], "-x");
00917 sprintf( exec_argv[i++], gdb_cmd_file);
00918 sprintf( exec_argv[i++], app_name);
00919 exec_argv[i++] = NULL;
00920 if (i >= MAX_ARGC) {
00921 fprintf( stderr, "E-SIC, too much arguments, exiting\n");
00922 sic_do_exit( 1);
00923 }
00924
00925
00926 printf( "I-SIC, Launching:");
00927 for (i = 0; argv[i] != NULL; i++)
00928 printf( " %s", argv[i]);
00929 printf( "\n");
00930
00931 return execvp( exec_argv[0], exec_argv);
00932 #endif
00933 #else
00934 return 0;
00935 #endif
00936 }
00937
00944 task_t sic_launch( int (*start_entry)( void *), void *data)
00945 {
00946 #ifndef WIN32
00947 pid_t pid = sic_fork( );
00948
00949 if (pid == 0) {
00950
00951 if ((*start_entry)( data) == -1)
00952 pid = - 1;
00953 }
00954
00955 return pid;
00956 #else
00957 DWORD dwThreadId;
00958 HANDLE hthrd;
00959
00960 hthrd = CreateThread(
00961 NULL,
00962 0,
00963 (LPTHREAD_START_ROUTINE) start_entry,
00964 data,
00965 0,
00966 &dwThreadId);
00967
00968
00969
00970 if (hthrd == NULL)
00971 sic_perror( "CreateThread");
00972
00973 return hthrd;
00974 #endif
00975 }
00976
00983 int sic_terminate( task_t task)
00984 {
00985 #ifndef WIN32
00986 if (kill( task, SIGTERM))
00987 return -1;
00988 if (waitpid( task, NULL, 0) == -1)
00989 return -1;
00990 #else
00991 if (!TerminateThread( task, 0)) {
00992 sic_pwarning( "TerminateThread");
00993 return -1;
00994 }
00995 #endif
00996 return 0;
00997 }
00998
01002 void sic_on_exit( )
01003 {
01004 static int recur_level = 0;
01005
01006 gag_trace( "<trace: sic_on_exit>");
01007 if (!recur_level) {
01008 recur_level++;
01009 if (sic_is_master( ))
01010 sic_destroy_comm_board( );
01011 else
01012 sic_close_comm_board( );
01013 }
01014
01015 gag_trace( "<trace: exit>");
01016 gag_trace_close( );
01017 }
01018
01024 void sic_do_exit( int status)
01025 {
01026 gag_trace( "<trace: sic_do_exit>");
01027
01028 exit( status);
01029 }
01030
01034 int sic_get_comm_id( )
01035 {
01036 return s_comm_board_id;
01037 }
01038
01046 int sic_open_comm_board( int comm_board_id)
01047 {
01048 if (comm_board_id == -1) {
01049 SIC_ASSERT( "sic_open_comm_board with bad id", 0);
01050 return -1;
01051 }
01052
01053 sic_init_handlers( );
01054
01055
01056 if (s_comm_board == NULL
01057 #ifdef SIC_DEBUG_COMM
01058 && comm_board_id >= 0
01059 #endif
01060 ) {
01061 #ifndef WIN32
01062 s_comm_board = sic_shm_attach( comm_board_id, sizeof( sic_comm_board_t));
01063 #else
01064 static sic_comm_board_t single_process_comm_board;
01065
01066 s_comm_board = &single_process_comm_board;
01067 #endif
01068 s_sem_comm_board = s_comm_board;
01069
01070 if (!sic_is_master( )) {
01071 if (s_comm_board->trace_fd >= 0)
01072 gag_trace_set_file_pointer( fdopen( s_comm_board->trace_fd, "w"));
01073
01074 #ifdef SIC_USE_SEM_OPEN
01075 static sic_comm_board_t process_local_sem_comm_board;
01076 s_sem_comm_board = &process_local_sem_comm_board;
01077 #endif
01078
01079 sic_sem_open( &s_sem_comm_board->comm_board_access);
01080 sic_sem_open( &s_sem_comm_board->draw_prompt);
01081 sic_sem_open( &s_sem_comm_board->write_command);
01082 sic_sem_open( &s_sem_comm_board->read_command);
01083 sic_sem_open( &s_sem_comm_board->widget_board_access);
01084 sic_sem_open( &s_sem_comm_board->widget_created);
01085 sic_sem_open( &s_sem_comm_board->listener_acquit);
01086 }
01087 }
01088 gag_trace( "<trace> sic_open_comm_board");
01089 return 0;
01090 }
01091
01095 void sic_close_comm_board( )
01096 {
01097 gag_trace( "<trace> sic_close_comm_board");
01098 if (s_comm_board != NULL) {
01099 #ifndef WIN32
01100 sync( );
01101 #endif
01102 sic_destroy_widget_board( );
01103 if (s_sem_comm_board != NULL) {
01104 sic_purge_listeners( sic_get_current_task( ));
01105 sic_sem_close( &s_sem_comm_board->comm_board_access);
01106 sic_sem_close( &s_sem_comm_board->draw_prompt);
01107 sic_sem_close( &s_sem_comm_board->write_command);
01108 sic_sem_close( &s_sem_comm_board->read_command);
01109 sic_sem_close( &s_sem_comm_board->widget_board_access);
01110 sic_sem_close( &s_sem_comm_board->widget_created);
01111 sic_sem_close( &s_sem_comm_board->listener_acquit);
01112 s_sem_comm_board = NULL;
01113 }
01114 sic_shm_detach( s_comm_board, sizeof( sic_comm_board_t));
01115 s_comm_board = NULL;
01116 }
01117 }
01118
01125 task_id_t sic_get_task_id( task_t task)
01126 {
01127 #ifndef WIN32
01128 return (task_id_t)task;
01129 #else
01130 return (task_id_t)(long long)task;
01131 #endif
01132 }
01133
01139 task_t sic_get_master_task( )
01140 {
01141 #ifdef SIC_DEBUG_COMM
01142 if (s_comm_board == NULL)
01143 return (task_t)0;
01144 #endif
01145
01146 return s_comm_board->master_task;
01147 }
01148
01154 task_id_t sic_get_master_task_id( )
01155 {
01156 return sic_get_task_id( sic_get_master_task( ));
01157 }
01158
01164 task_t sic_get_current_task( )
01165 {
01166 #ifndef WIN32
01167 return getpid( );
01168 #else
01169 return GetCurrentThread( );
01170 #endif
01171 }
01172
01178 task_id_t sic_get_current_task_id( )
01179 {
01180 return sic_get_task_id( sic_get_current_task( ));
01181 }
01182
01188 void sic_set_ctrlc_handled( int handled)
01189 {
01190 s_ctrlc_handled = handled;
01191 }
01192
01196 void sic_send_ctrlc( )
01197 {
01198 #ifndef WIN32
01199 kill( sic_get_master_task( ), SIGINT);
01200 #else
01201 sic_do_exit( 0);
01202 #endif
01203 }
01204
01208 void sic_post_prompt( const command_line_t *command_line)
01209 {
01210 gag_trace( "<trace> sic_post_prompt");
01211 s_comm_board->command_line = *command_line;
01212 sic_sem_post( &s_sem_comm_board->draw_prompt);
01213 }
01214
01222 int sic_wait_prompt( command_line_t *command_line, int timeout)
01223 {
01224 int ret;
01225
01226 #ifdef SIC_DEBUG_COMM
01227 if (s_comm_board == NULL)
01228 return 0;
01229 #endif
01230
01231 gag_trace( "<trace: enter> sic_wait_prompt");
01232 ret = sic_sem_timed_wait( &s_sem_comm_board->draw_prompt, timeout);
01233 if (ret == 0) {
01234 *command_line = s_comm_board->command_line;
01235 }
01236 gag_trace( "<trace: leave> sic_wait_prompt");
01237 return ret;
01238 }
01239
01245 void sic_get_current_prompt( char prompt[])
01246 {
01247 strncpy( prompt, s_comm_board->command_line.prompt, PROMPT);
01248 }
01249
01256 int sic_push_command_text( const char *text)
01257 {
01258 gag_trace( "<trace: enter> sic_push_command_text");
01259
01260 if (s_comm_board->pushed_command_text[0]) {
01261 gag_trace( "<trace: leave> sic_push_command_text return error");
01262 return -1;
01263 }
01264
01265 strncpy( s_comm_board->pushed_command_text, text, MAXBUF);
01266 gag_trace( "<command: push> \"%s\"", text);
01267 sic_sem_post( &s_sem_comm_board->read_command);
01268
01269 gag_trace( "<trace: leave> sic_push_command_text");
01270 return 0;
01271 }
01272
01280 int sic_post_command_from( const command_line_t *command_line, sic_command_from_t from)
01281 {
01282 return sic_raw_post_command_from( command_line, 2000, from);
01283 }
01284
01291 int sic_post_command( const command_line_t *command_line)
01292 {
01293 return sic_post_command_from( command_line, SIC_DEFAULT);
01294 }
01295
01301 void sic_post_command_from_prompt( const command_line_t *command_line)
01302 {
01303 sic_raw_post_command_from( command_line, -1, SIC_KEYBOARD);
01304 }
01305
01313 int sic_post_command_text_from( const char *text, sic_command_from_t from)
01314 {
01315 command_line_t command_line;
01316
01317 sic_build_command_line( text, &command_line);
01318
01319 return sic_post_command_from( &command_line, from);
01320 }
01321
01328 int sic_post_command_text( const char *text)
01329 {
01330 return sic_post_command_text_from( text, SIC_DEFAULT);
01331 }
01332
01339 int sic_post_command_va( const char *args, va_list l)
01340 {
01341 char command[MAXBUF];
01342 vsprintf( command, args, l);
01343
01344 return sic_post_command_text( command);
01345 }
01346
01353 int sic_post_command_args( const char *args, ...)
01354 {
01355 int ret;
01356 va_list l;
01357
01358 va_start( l, args);
01359 ret = sic_post_command_va( args, l);
01360 va_end( l);
01361
01362 return ret;
01363 }
01364
01371 void sic_wait_command( command_line_t *command_line, sic_command_from_t *from)
01372 {
01373 gag_trace( "<trace: enter> sic_wait_command");
01374 if (!s_comm_board->pushed_command_text[0])
01375 sic_sem_post( &s_sem_comm_board->write_command);
01376 sic_sem_wait( &s_sem_comm_board->read_command);
01377 if (!s_comm_board->pushed_command_text[0]) {
01378 *command_line = s_comm_board->command_line;
01379 *from = s_comm_board->from;
01380 } else {
01381 sic_build_command_line( s_comm_board->pushed_command_text, command_line);
01382 *from = SIC_DEFAULT;
01383 s_comm_board->pushed_command_text[0] = '\0';
01384 }
01385 gag_trace( "<command: receive> \"%s%s\"", command_line->prompt, command_line->line);
01386
01387 gag_trace( "<trace: leave> sic_wait_command");
01388 }
01389
01394 void sic_create_widget_board( )
01395 {
01396 gag_trace( "<trace> sic_create_widget_board");
01397 if (s_comm_board->widget_board_id < 0) {
01398 sprintf( s_widget_shm_name, "/SIC_%d_W", sic_get_current_task_id( ));
01399 s_comm_board->widget_board_id = sic_shm_create( s_widget_shm_name, sizeof( sic_widget_board_t));
01400 }
01401 sic_open_widget_board( );
01402 s_widget_board->widget_count = 0;
01403 }
01404
01412 void sic_set_widget_global_infos( const char window_title[], const char help_filename[], const char returned_command[])
01413 {
01414 strcpy( s_widget_board->window_title, window_title);
01415 strcpy( s_widget_board->help_filename, help_filename);
01416 strcpy( s_widget_board->returned_command, returned_command);
01417 }
01418
01424 void sic_set_widget_returned_command( const char returned_command[])
01425 {
01426 #ifdef SIC_DEBUG_COMM
01427 if (s_comm_board == NULL)
01428 return;
01429 #endif
01430
01431 strcpy( s_widget_board->returned_command, returned_command);
01432 }
01433
01439 void sic_get_widget_returned_command( char returned_command[])
01440 {
01441 strcpy( returned_command, s_widget_board->returned_command);
01442 }
01443
01449 void sic_set_widget_returned_code( int code)
01450 {
01451 #ifdef SIC_DEBUG_COMM
01452 if (s_comm_board == NULL)
01453 return;
01454 #endif
01455
01456 s_widget_board->returned_code = code;
01457 }
01458
01464 int sic_get_widget_returned_code( )
01465 {
01466 return s_widget_board->returned_code;
01467 }
01468
01474 void sic_add_modified_variable_listener( sic_modified_variable_listener_t l)
01475 {
01476 sic_listener_handler_t h = {
01477 (task_t)NULL,
01478 SIC_MODIFIED_VARIABLE_EVENT,
01479 NULL,
01480 #ifndef WIN32
01481 SIGUSR2
01482 #else
01483 0
01484 #endif
01485 };
01486 h.task = sic_get_current_task( );
01487 h.listener = l;
01488 sic_record_listener( &h);
01489 }
01490
01496 void sic_fire_modified_variable_event( const sic_widget_def_t *widget)
01497 {
01498 gag_trace( "<trace: enter> sic_fire_modified_variable_event");
01499 sic_open_widget_board( );
01500 s_widget_board->modified_widget = *widget;
01501 sic_trigger_listeners( SIC_MODIFIED_VARIABLE_EVENT);
01502 sic_close_widget_board( );
01503 gag_trace( "<trace: leave> sic_fire_modified_variable_event");
01504 }
01505
01511 void sic_add_redraw_prompt_listener( sic_redraw_prompt_listener_t l)
01512 {
01513 sic_listener_handler_t h = {
01514 (task_t)NULL,
01515 SIC_REDRAW_PROMPT_EVENT,
01516 NULL,
01517 #ifndef WIN32
01518 SIGUSR2
01519 #else
01520 0
01521 #endif
01522 };
01523 h.task = sic_get_current_task( );
01524 h.listener = l;
01525 sic_record_listener( &h);
01526 }
01527
01533 void sic_fire_redraw_prompt_event( const command_line_t *command_line)
01534 {
01535 gag_trace( "<trace: enter> sic_fire_redraw_prompt_event");
01536 s_comm_board->command_line = *command_line;
01537 sic_trigger_listeners( SIC_REDRAW_PROMPT_EVENT);
01538 gag_trace( "<trace: leave> sic_fire_redraw_prompt_event");
01539 }
01540
01544 void sic_suspend_prompt( )
01545 {
01546 fprintf( stderr, "%s\n", s_comm_board->command_line.line);
01547 }
01548
01555 int sic_add_widget_def( sic_widget_def_t *def)
01556 {
01557 if (s_widget_board->widget_count >= SIC_MAX_WIDGET_ON_BOARD)
01558 return -1;
01559
01560 s_widget_board->widgets[s_widget_board->widget_count++] = *def;
01561
01562 return 0;
01563 }
01564
01571 void sic_set_widget_def( int index, const sic_widget_def_t *widget)
01572 {
01573 s_widget_board->widgets[index] = *widget;
01574 }
01575
01579 void sic_destroy_widget_board( )
01580 {
01581 gag_trace( "<trace> sic_destroy_widget_board");
01582 if (s_widget_board != NULL) {
01583 sic_shm_detach( s_widget_board, sizeof( sic_widget_board_t));
01584 s_widget_board = NULL;
01585 }
01586
01587 if (sic_is_master( ) && s_comm_board->widget_board_id >= 0) {
01588 sic_shm_destroy( s_widget_shm_name, s_comm_board->widget_board_id);
01589 s_comm_board->widget_board_id = -1;
01590 }
01591 }
01592
01599 int sic_open_widget_board( )
01600 {
01601 #ifdef SIC_DEBUG_COMM
01602 if (s_comm_board == NULL)
01603 return 0;
01604 #endif
01605
01606 gag_trace( "<trace: enter> sic_open_widget_board");
01607 sic_sem_wait( &s_sem_comm_board->widget_board_access);
01608 if (s_widget_board == NULL) {
01609 #ifndef WIN32
01610 s_widget_board = sic_shm_attach( s_comm_board->widget_board_id, sizeof( sic_widget_board_t));
01611 #else
01612 static sic_widget_board_t single_process_widget_board;
01613
01614 s_widget_board = &single_process_widget_board;
01615 #endif
01616 }
01617 gag_trace( "<trace: leave> sic_open_widget_board");
01618 return s_widget_board->widget_count;
01619 }
01620
01628 void sic_get_widget_global_infos( char window_title[], char help_filename[], char returned_command[])
01629 {
01630 #ifdef SIC_DEBUG_COMM
01631 if (s_comm_board == NULL)
01632 return;
01633 #endif
01634
01635 strcpy( window_title, s_widget_board->window_title);
01636 strcpy( help_filename, s_widget_board->help_filename);
01637 strcpy( returned_command, s_widget_board->returned_command);
01638 }
01639
01646 void sic_get_widget_def( int index, sic_widget_def_t *widget)
01647 {
01648 *widget = s_widget_board->widgets[index];
01649 }
01650
01654 void sic_close_widget_board( )
01655 {
01656 #ifdef SIC_DEBUG_COMM
01657 if (s_comm_board == NULL)
01658 return;
01659 #endif
01660
01661 gag_trace( "<trace> sic_close_widget_board");
01662 sic_sem_post( &s_sem_comm_board->widget_board_access);
01663 }
01664
01668 void sic_post_widget_created( )
01669 {
01670 gag_trace( "<trace> sic_post_widget_created");
01671 sic_sem_post( &s_sem_comm_board->widget_created);
01672 }
01673
01677 void sic_wait_widget_created( )
01678 {
01679 gag_trace( "<trace: enter> sic_wait_widget_created");
01680 sic_sem_wait( &s_sem_comm_board->widget_created);
01681 gag_trace( "<trace: leave> sic_wait_widget_created");
01682 }
01683