Operating System - OpenVMS
cancel
Showing results for 
Search instead for 
Did you mean: 

Mapping to global sections with FORTRAN and C

 
Highlighted
Advisor

Mapping to global sections with FORTRAN and C

We have a legacy FORTRAN product that makes extensive use of global sections. We now have a process written in C that we want to be able to map to the existing global sections.
When we attempt to map, we get error 4042 - invalid argument. BTW, we are running on an Integrity server.
Anyone seen this problem before? Know of any examples of using the mgblsc system service from C to map to an existing global section created by a FORTRAN program via the crmpsc system service?
18 REPLIES 18
Highlighted
Honored Contributor

Re: Mapping to global sections with FORTRAN and C

I know nothing, but I read that SS$_INVARG
implies this:

Invalid argument specified to service. Common
sources are the incorrect specification of
relpag or the values in the inadr array.


Not being able to see any of what you're
doing (in Fortran or C) makes it hard for a
non-psychic like me to discern much about
what you might be doing wrong.
Highlighted
Honored Contributor

Re: Mapping to global sections with FORTRAN and C

The usual cause of an "%SYSTEM-E-INVARG, invalid argument" invalid argument error is, well, an invalid argument. A bad parameter on the failing call.

See the discussion of the SS$_INVARG error in this context in the Programming Concepts documentation materials located here:

http://h71000.www7.hp.com/doc/82final/5841/5841pro_041.html

As for examples, those are (among other places) here:

http://h71000.www7.hp.com/wizard/swdev/gblsec.c

http://h71000.www7.hp.com/wizard/wiz_2486.html

http://www.eight-cubed.com/examples/framework.php?file=sys_gs64.c



Highlighted
Honored Contributor

Re: Mapping to global sections with FORTRAN and C

Scot,

As Steven mentioned, the only way to identify what is happening is to review the sources.

- Bob Gezelter, http://www.rlgsc.com
Highlighted
Honored Contributor

Re: Mapping to global sections with FORTRAN and C

Scot,

Taking a wild guess, the most likely suspect is your inadr argument to $CRMPSC and/or $MGBLSC, defining the range of addresses to be mapped. On older systems the interpretation was fairly lax. Newer systems require the addresses to be down to the byte on the starting page and ending page.

$ help system $mgblsc arg

...

inadr

OpenVMS usage:address_range
type: longword (unsigned)
access: read only
mechanism: by reference
Starting and ending virtual addresses into which the section is to be mapped. The inadr argument is the address of a 2-longword array containing, in order, the starting and ending process virtual addresses. Only the virtual page number portion of each virtual address is used to specify which pages are to be mapped; the low-order byte-within-page bits are ignored for this purpose.

The interpretation of the inadr argument depends on the setting of SEC$M_EXPREG in the inadr argument and whether you are using an Alpha, an I64, or a VAX system. Refer to the HP OpenVMS System Services Reference Manual for a complete description of these differences.

...

Run your program under DEBUG control and STEP/INTO the system service, then examine your argument list to make sure you're sending exactly what you think you're sending. My bet it you aren't.

I'd also strongly recommend you build an access module around your global section, rather than access the naked bits. Be especially careful about data alignment. Examine compiler listings (use cross reference maps) to confirm that the compilers really have placed fields at the same offsets.

You also MUST (absolutely, positively, without exception) synchronize access to the data. I don't care if you believe you have only one writer and that makes it all OK, all data directly shared between processes MUST be synchronized correctly. The lock manager is simple to use and will protect you from having to debug weird, impossible to reproduce, timing bugs.
A crucible of informative mistakes
Highlighted
Trusted Contributor

Re: Mapping to global sections with FORTRAN and C

Please post, preferably as an attachment that retains the original formatting, the relevant extract of your code. It might also be worth mentioning the values of any parameters. (This could be as little as a few lines or if there's relevant code just before your system service call that might blow out to 15 or 20 lines. Don't attach what's not relevant to your problem.)

BTW, did you just cut and paste the Fortran code, then make a few tweaks before you tried running with it? You might be hitting pass-by-reference and pass-by-value conflicts.
Highlighted
Advisor

Re: Mapping to global sections with FORTRAN and C

Hi,

Thanks to all. Your input proved useful. I fixed the arguments, but now encountered a different problem. I spawned both images (a Fortran and a C executable) in debug mode, and looked at the values. The RETADR match the INADR of the FORTRAN program, meaning $CRMPSC system call is successful.

The INADR of C match the one in Fortran, but RETADR is meaningless, and $MGBLSC returns exit code 12 (access violation).

FYI, the INADR arrays of both the Fortran and C contain the same values.

The condensed source codes of both programs are below. My apologies for code alignment issues due to window sizing in the reply window:


PROGRAM A (Fortran)

definitions.....

common /xyz/ abc,def,ghi

flgl = sec$m_wrt .OR.
sec$m_gbl .OR.
sec$m_dzro .OR.
sec$m_perm .OR.
sec$m_pagfil .OR. sec$m_wrt

maprange(1) = %loc(abc)
maprange(2) = %loc(ghi)
i = lib$getsyi (%loc(syi$_page_size),
CPU_PAGE_SIZEL,,
SIZEOF(CPU_PAGE_SIZEL),,)
templ = mod (maprange(2),
CPU_PAGE_SIZEL)
if (templ .ne. 0)
1 maprange(2) = maprange(2) +
1 (CPU_PAGE_SIZEL - templ - 1)
sizel = (maprange(2) - maprange
1 (1)) / 512 + 1

i= SYS$CRMPSC (maprange, retrange,
0, %val(flgl), 'BSCOM', ,
%val(0), ,%val(sizel), , ,)
abc=10
def=20

loop...do something...

end


PROGRAM B (C program)

#include
...other includes....

#pragma extern_model common_block
struct xs
{
unsigned long int abc;
unsigned long int def;
unsigned long int ghi;
};

extern struct xs xyz;

unsigned long int starange[2];
unsigned long int maprange[2];
char *gsdnam = "BSCOM";
unsigned long int flag = SEC$M_GBL |
SEC$M_WRT | SEC$M_PAGFIL |
SEC$M_DZRO | SEC$M_PERM;
...other definitions.....

starange[0] = (unsigned long int)
&xyz.abc;
starange[1] = (unsigned long int)
&xyz.ghi;

templ = (starange[1] % 8192);
if (templ != 0){
starange[1] = (starange[1] +
(8192 - templ - 1));
}
sizel = ((starange[1] - starange
[0]) / 512 + 1);

statl = SYS$MGBLSC (&starange,
&maprange, 0, flag, *gsdnam,
0, 0);

printf ("Status for MGBLSC is
%d\n",statl);
printf ("This value is from fortran
%d\n", xyz.abc);

return;
Highlighted
Honored Contributor

Re: Mapping to global sections with FORTRAN and C

Without checking all details,
one obvious error in the C code:
gsdnam must be passed by descriptor, but the code passes a pointer to a C string.

Change it to:
#include descrip

$DESCRIPTOR(gsdnam, "BSCOM");

Then pass &gsdnam as parameter to $crmpsc.


http://www.mpp.mpg.de/~huber
Highlighted
Honored Contributor

Re: Mapping to global sections with FORTRAN and C

That C code looks vert much like Fortran code, coded in C. (Been there, done that, and have the battle scars.)

8192? Either hard-code 64K alignment, or grab the page size value SYI$_PAGE_SIZE of the running system from sys$getsyi. I don't know if there are currently plans to change the page size, but there were certainly various similar recommendations over the years; there were various recommendations to avoid hardcoding alignments to the 8 KiB page size.

And I'd probably use a #define to represent that 8192 value, or the 65536 value, regardless. Be kind to whomever will support this code.

from pagedef.h:

#define MMG$C_VAX_PAGE_SIZE 512 /* SIZE OF VAX PAGE */
#define MMG$C_ALPHA_MAX_PAGE_SIZE 65536 /* MAX. PAGE SIZE */
$

And as for alignment and rounding, something akin to:

size_rounded = ((value + 8191) & 8191);
addr_rounded = value & 8191;

also works. ( With 8192 or with MMG$C_ALPHA_MAX_PAGE_SIZE, or...)

Use pointers and position-independence to access the contents of the global section where you can. Fortran does those now, as does C. Using COMMON_BLOCK means you have to align virtual memory across processes, and maintaining code that does that gets interesting.

#include

#define __NEW_STARLET to 1 if you want to turn on better argument-passing and parameter diagnostics, too.

IThe other approach is to avoid the $creprc and (if you're using a COMMON), just link the COMMON reference stuff directly into the image. That's more or less what this does:

http://h71000.www7.hp.com/wizard/wiz_2486.html

And yes, you need a descriptor for the section name, and a $VMS_STATUS_SUCCESS( status_value) test or a direct low-bit test to verify that the $crmpsc call actually worked is recommended.

Highlighted
Regular Advisor

Re: Mapping to global sections with FORTRAN and C

stupid question: Hoff the example you gave at http://h71000.www7.hp.com/wizard/swdev/gblsec.c

what is it achieving ? I am trying to understand why global sections are used in programming , where can i find some basic info about it ?

thanks
Sami