/* © Copyright 2005 Hewlett-Packard Development Company, L.P. Consistent with FAR 12.211 and 12.212, Commercial Computer Software, Computer Software Documentation, and Technical Data for Commercial Items are licensed to the U.S. Government under vendor's standard commercial license. */ /* PROGRAM NAME: FORMS$DEMO_THREADED_TIMER.C PROGRAM DESCRIPTION: This program is an example that shows how to use POSIX threads to update a field with DECforms. In this program, we update a field with the current time. However, the method is generally applicable to updating a field on the screen with any information -- asynchronously. AUTHOR: Hewlett-Packard Development Company, L.P. CREATION DATE: Oct-1995 History: * Begin Itanium port. * This is the first phase of the Itanium port. System is * updated to compile/link with latest versions of the * compilers. The next phase of the Itanium port will be * to cross-compile on Alpha. * 16-Jul-2003 AFL Changes to use current compilers and libraries, refer to note conference * CAMINO::SYS$SYSDEVICE:[NOTES$LIBRARY]DECFORMS-IPF-PORT.NOTE for more information. * (removed declaration of function "exit", see Note 56) * 30-Aug-2005 Binny Conditionalise for Code merge. ------ Instructions ------ If your system manager copied the Sample from the DECforms kit onto your system, you can run the DECforms Sample Timer Application by doing the following: $ RUN FORMS$EXAMPLES:FORMS$DEMO_THREADED_TIMER The DECforms INTRODUCTORY Sample Checking Application in the C language consists of two files: FORMS$DEMO_THREADED_TIMER_C.C The application itself FORMS$DEMO_THREADED_TIMER_FORM.IFDL The IFDL source form Both files are copied from the DECforms kit to the FORMS$EXAMPLES directory. Putting the files in FORMS$EXAMPLES is an installation option; talk to your system manager if they aren't there. A working version of the application can be created in your own directory from these sources by doing the following: $! Set the default to your own directory: $ SET DEFAULT yourdirectory $ $! Copy all the sources files from FORMS$EXAMPLES to your own directory: $ COPY FORMS$EXAMPLES:FORMS$DEMO_THREADED_TIMER.C, - FORMS$DEMO_THREADED_TIMER_FORM.IFDL [] $! Compile the C source: $ CC FORMS$DEMO_THREADED_TIMER.C $ $! Translate the IFDL source form: $ FORMS TRANSLATE FORMS$DEMO_THREADED_TIMER_FORM.IFDL $ $! Extract an object module from the binary form: $ FORMS EXTRACT OBJECT FORMS$DEMO_THREADED_TIMER_FORM.FORM $ $! Link the C and the Form objects: $! With VAX C: $ LINK FORMS$DEMO_THREADED_TIMER.OBJ, FORMS$DEMO_THREADED_TIMER_FORM.OBJ, - SYS$INPUT/OPTIONS SYS$SHARE:CMA$OPEN_RTL/SHARE SYS$LIBRARY:VAXCRTL.OLB/LIB $! With DEC C: $ LINK FORMS$DEMO_THREADED_TIMER.OBJ, FORMS$DEMO_THREADED_TIMER_FORM.OBJ, - SYS$INPUT/OPTIONS SYS$SHARE:CMA$OPEN_RTL/SHARE ! ! note that FORMS$AR_FORM_TABLE must be specified in the FORMS$ENABLE call ! to locate the form in memory You can then run the executable in your own directory by simply typing: $ RUN FORMS$DEMO_THREADED_TIMER How It Works ------------ The method used is to enable TWO sessions to the same form - one for the normal main form work and the other for the threaded work. Once the two sessions are enabled a single SEND is performed from the main routine and a thread is created to perform the timer function. The normal main routine then waits in a simple RECEIVE loop for user input. Related form file: forms$demo_threaded_timer_form.ifdl The form DEMO_THREADED_TIMER_FORM is here. It has two form records: TIMER - for the timer thread send and MAIN - for a main thread receive. */ /* * The DECforms definitions */ #include #include #include #include #include /* * A simple macro to construct a string descriptor for a structure */ #define $STRUCTURE_DESCRIPTOR(name,rec) struct dsc$descriptor_s name = {sizeof(rec), DSC$K_DTYPE_T, DSC$K_CLASS_S, (char *)&rec} /* A session desc must be used on every call to the FORMS$... subroutines. */ char timer_session_buffer[] = " "; char main_session_buffer[] = " "; $DESCRIPTOR (timer_session_desc, timer_session_buffer); $DESCRIPTOR (main_session_desc, main_session_buffer); $DESCRIPTOR (term_desc, "SYS$INPUT"); $DESCRIPTOR (form_name_desc, "DEMO_THREADED_TIMER_FORM"); $DESCRIPTOR (watch_desc, " -Watch this space- "); typedef struct _Item_List { short buff_length; short code; char *buff_addr; int length_returned; } Item_List; struct timer_record_struct { char ast_time_field[23]; } timer_record; struct main_record_struct { char f1[8]; char f2[8]; } main_record; pthread_t timer_thread; char empty_field[] = " "; $STRUCTURE_DESCRIPTOR (main_record_desc, main_record); $STRUCTURE_DESCRIPTOR (timer_record_desc, timer_record); $DESCRIPTOR (main_name_desc, "MAIN"); $DESCRIPTOR (timer_name_desc, "TIMER"); /* Commented out to solve the information that triggered with the new complier as the returned type of the extrnal */ /* function (exit) defined as int but the compiler expected it as void. */ /* Refer to Note 56 for more details. */ /* Conditionalised for Code merge */ #ifndef __ia64 extern exit(); #endif extern lib$date_time(); extern lib$signal(); void check_forms_status (int status) { /* * Check the parameter for success. * If not success, print error message and stop. */ if (status && ((status % 2)==0)) { /* if even */ lib$signal (status); exit (1); } } void forms_demo_timer (struct dsc$descriptor_s *session_desc) { struct timespec delay = { 1, 0 }; int status; while (1) { /* Go to sleep for a second */ pthread_delay_np (&delay); /* Get the current date/time */ status = lib$date_time (&timer_record_desc); check_forms_status (status); /* SEND to the timer session at ast level */ status = forms$send (session_desc, /* session id */ &timer_name_desc, /* record name in form */ &1, /* Number of records sent */ 0,0, /* Receive ctl text msg/count*/ 0,0, /* Send ctl text msg/count */ 0, /* timeout */ 0, /* parent request id */ 0, /* request options item list*/ &timer_record_desc, /* the record */ 0); /* shadow record */ check_forms_status (status); pthread_testcancel (); } } int main (int argc, char *argv[]) { int status; /* Start the two sessions... */ /* Start the main session */ status = forms$enable (&forms$ar_form_table, /* Vector address */ &term_desc, /* Device name */ &main_session_desc, /* session id returned */ 0, /* Name of form file */ &form_name_desc, /* Name of form */ 0, /* Receive ctl msg */ 0, /* Receive ctl ct */ 0, /* Send ctl msg */ 0, /* Send ctl ct */ 0, /* Timeout */ 0, /* Parent request id */ 0); /* request options item list */ check_forms_status (status); /* Start the timer session */ status = forms$enable (&forms$ar_form_table, /* Vector address */ &term_desc, /* Device name */ &timer_session_desc, /* session id returned */ 0, /* Name of form file */ &form_name_desc, /* Name of form */ 0, /* Receive ctl msg */ 0, /* Receive ctl ct */ 0, /* Send ctl msg */ 0, /* Send ctl ct */ 0, /* Timeout */ 0, /* Parent request id */ 0); /* request options item list */ check_forms_status (status); /* SEND to the AST session at non-ast level */ status = forms$send (&timer_session_desc, /* session id */ &timer_name_desc, /* record name in form */ &1, /* Number of records sent */ 0,0, /* Receive ctl text msg/count */ 0,0, /* Send ctl text msg/count */ 0, /* timeout */ 0, /* parent request id */ 0, /* request options item list*/ &watch_desc, /* the record */ 0); /* shadow record */ check_forms_status (status); /* Start the timer thread for the SEND(s) */ /* The new compaq ODL contains new syntax for pthread_create function, which indicates that, the parameters: */ /* - pthread_startroutine_t and pthread_addr_t should be replaced with (void *) */ /* - pthread_attr_default should be replaced with NULL. */ /* Refer to Note 55 for more details. */ /* Conditionalised for Code merge */ #ifdef __ia64 status = pthread_create (&timer_thread, NULL, (void*) forms_demo_timer, &timer_session_desc); #else status = pthread_create (&timer_thread, pthread_attr_default, (pthread_startroutine_t) forms_demo_timer, &timer_session_desc); #endif check_forms_status (status); /* Main RECEIVE loop */ while (1) { /* RECEIVE the main-thread record */ status = forms$receive ( &main_session_desc, &main_name_desc, &1, 0,0, 0,0, 0, 0, 0, &main_record_desc, 0); check_forms_status (status); /* Check for quitting */ /* Quit if both blank */ if (strncmp(main_record.f1, empty_field, 8) == strncmp(main_record.f2, empty_field, 8)) { pthread_cancel (timer_thread); /* The new compaq ODL contains new syntax for pthread_join function, which indicates that, the parameter: */ /* pthread_addr_t should be replaced with (void *) */ /* Refer to Note 55 for more details. */ /* Conditionalised for Code merge */ #ifdef __ia64 pthread_join (timer_thread, (void*) &status); #else pthread_join (timer_thread, (pthread_addr_t) &status); #endif check_forms_status (status); status = forms$disable (&timer_session_desc); check_forms_status (status); status = forms$disable (&main_session_desc); check_forms_status (status); exit (1); } } }