/* COPYRIGHT (c) 1995 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS. THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY TRANSFERRED. THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION. DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL. */ /* 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: Digital Equipment Corporation CREATION DATE: Oct-1995 ------ 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"); extern exit(); 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) */ status = pthread_create (&timer_thread, pthread_attr_default, (pthread_startroutine_t) forms_demo_timer, &timer_session_desc); 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); pthread_join (timer_thread, (pthread_addr_t) &status); 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); } } }