I am just getting into mainframe development so excuse any ignorance, but is there a way to identify which map is being displayed or was last sent to the terminal?
For example, I have MAP1 & MAP2 in mapset MAPS. The maps would alternate by the press of a PF key (PF7/PF8). On each map the user can enter a value to be evaluated by the program (SLCTOPTI). Is there a proper way to determine which map should be evaluated when receiving from the user?
Here's what I currently have to attempt this:
** some code before **
WHEN DFHENTER
+0103
%+0104 IF CURRENT-MAP-SCREEN = 1
%+0104 EXEC CICS RECEIVE
%+0104 MAP ('MAP1')
%+0104 INTO (MAP1I)
%+0104 RESP (WS-RESP)
%+0104 END-EXEC
%+0104 ELSE
%+0104 EXEC CICS RECEIVE
%+0104 MAP ('MAP2')
%+0104 INTO (MAP2I)
%+0104 RESP (WS-RESP)
%+0104 END-EXEC
%+0104 END-IF
+0103
%+0104 EVALUATE SLCTOPTI
+0103
%+0104 WHEN ' 1'
%+0104 WHEN '01'
%+0104 WHEN '1'
+0103
%+0104 MOVE 'XXXX' TO WS-START-TRAN
%+0104
%+0104 WHEN ' 2'
%+0104 WHEN '02'
%+0104 WHEN '2'
+0103
%+0104 MOVE 'XXXX' TO WS-START-TRAN
** some code after **
I'm not sure if this works yet, but I would like to know if there is already a command for this or a better way to do it.
Presuming CURRENT-MAP-SCREEN is set to indicate which map is being sent when you send the map to the screen and is stored in your DFHCOMMAREA, this is how I normally see it done.
Normally, the way a pseudo-conversational CICS transaction's initial program is written is to check for EIBCALEN = 0 which indicates this is the initial invocation of the transaction. EIBCALEN (the CALEN is an abbreviation for Communication Area LENgth) is a field in the EIB (the Execute Interface Block) which is automatically passed to your transaction's initial program (as DFHEIBLK) and inserted into your Linkage Section by either the precompiler or the coprocessor (whichever you are using). The EIB contains a number of fields describing the context of your transaction.
If EIBCALEN = 0 you know to initialize your WS-COMMAREA, send your initial map, store the indicator of which map you sent in CURRENT-MAP-SCREEN, and EXEC CICS RETURN TRANSID(EIBTRNID) COMMAREA(WS-COMMAREA) LENGTH(...).
Your transaction's initial program is also automatically passed a pointer to the DFHCOMMAREA, also automatically inserted into your Linkage Section by either the precompiler or the coprocessor (whichever you are using). The DFHCOMMAREA is preserved on your behalf by CICS between invocations of your transaction.
If EIBCALEN NOT = 0 you know to MOVE DFHCOMMAREA TO WS-COMMAREA and check CURRENT-MAP-SCREEN to see which map to RECEIVE.
When you EXEC CICS RETURN TRANSID(EIBTRNID) COMMAREA(WS-COMMAREA) LENGTH(...) you are providing CICS with the data to be preserved and passed back to your transaction's initial program in the DFHCOMMAREA on its next invocation. The memory allocated for your Working-Storage and Local-Storage is freed once the EXEC CICS RETURN happens.
It is very common for people to MOVE DFHCOMMAREA TO WS-COMMAREA and then work with the copy of the data in their Working-Storage. If EIBCALEN = 0 you don't do this of course, there's no data to move.
Some shops try to have a 1:1 relationship between programs and maps to eliminate the need to keep track of which map is currently displayed.
Hopefully later in your studies your instructor will talk about using channels and containers instead of the DFHCOMMAREA. The latter is how CICS applications were built for several decades so you will definitely see code written this way, the former is a newer capability.
The System Programming Interface (SPI) has options MAPNAME and MAPSETNAME n the INQUIRE TERMINAL COMMAND. Your four character terminal identifier is available in the EXEC Interface Block (EIB) as field EIBTRMID.
A task's EIB is available to every task running in CICS, in most languages it is directly available and fields can be used by name directly although in C you have to ask CICS for its address using EXEC CICS ADDRESS EIB.
Related
I'm interesting in testing some of the limits of Gforth and would like to have it execute arbitrary code that I "hand compile" into allocated memory. Here is my attempt.
100 cells allocate throw constant &mem
\ store at &mem: docol: . EXIT
docol: &mem !
comp' . &mem 1 cells + ! drop \ drop "execution token"
comp' EXIT &mem 2 cells + ! drop
42 \ something to print
&mem execute
Unfortunately this fails with:
in file included from *OS command line*:-1
notes/execute.fs:8: Invalid memory address
&mem >>>execute<<<
Backtrace:
$7EFC61175B28 execute
I have to use comp' instead of ', because it doesn't work for getting the xt of EXIT.
I would have thought this should work, unless Gforth doesn't operate in any way like JonesForth did where docol: starts executing the xt's next to it.
Is this possible in either Gforth or ANS forth in general?
You can execute an arbitrary list of xt, but you have to use your own word to execute this list, by applying execute to each xt from the list.
By the current standard, a standard program cannot compile arbitrary code into allocated memory. The program may only compile into the code space of the dictionary, and in the frame of the current definition (i.e., that is not yet completed). Compilation can be performed via compile, ( xt -- ) or postpone ( i*x "name" -- j*x ) words. Also the words literal, 2literal, sliteral, fliteral (or their counterparts lit,, 2lit,, slit,, flit,) can be used to compile literals.
In Gforth you can also compile into another dictionary ("section"), that can be allocated using word extra-section ( size "name" -- ).
10000 extra-section execute-in-my-section
\ execute-in-my-section ( i*x xt -- j*x )
unused cr . \ free space in the default dictionary
[:
unused cr . \ free space in the current section
:noname
postpone .
postpone ;
( xt-new )
unused cr . \ free space after compile the new definition
;] execute-in-my-section ( xt-new )
\ test
123 swap execute
See also section.fs source, and Sections paper by Anton Ertl, 2016.
1 the stored procedure
create procedure sp_count_demo(
i_user_id varchar(30)
)
returning p_count as num_of_row ;
define p_count integer ;
set isolation to dirty read ;
let p_row = 0 ;
select count(*)
into p_count
from some_table a
where a.user_id = i_user_id
;
return p_row;
end procedure ;
2 The procedure at (1) will be called from java webapps with connection pool
3 Do I need to set the isolation level back to previous value before returning the result? (ie to avoid another process reusing the connection from having "dirty read" isolation level)
4 What is the default isolation level
5 Where/How can I get the default value for isolation level
Thanks in advance
Since a connection pool is in use the stored procedure should return the isolation level to its previous setting in order to avoid unexpected results when another app uses the same connection. The default isolation level depends on the logging mode of the database:
For an unlogged database it will effectively be "Dirty Read" (shown as NL by the onstat -g ses command).
For a mode ANSI database it will be "Repeatable Read."
For other logged databases it will be "Committed Read."
The onconfig parameter USELASTCOMMITTED can also be used to change how the default isolation level is used. More information on that can be found in the Knowledge Center (search on USELASTCOMMITTED).
It is possible for a session to find out its current isolation level using a query against the sysmaster database. This query was run on Informix 12.10 but should also be valid for 11.70:
select tx.isolevel
from sysmaster:systxptab tx, sysmaster:sysrstcb r, sysmaster:sysscblst s
where s.address = r.scb and tx.owner = r.address
and s.sid = dbinfo("sessionid");
It returns the isolation level as an integer which is an internal value - for example committed read has value 2. I don't believe the mapping of isolation level to integer value is published so you will need to experiment with setting different levels for a session and then running the above query.
There's variable in my module, and there's receive method to renew variable value. And multiple process are calling this method simultaneously. I need lock this variable when one process is modifying it. Sample as below
mytest.erl
%%%-------------------------------------------------------------------
-module(mytest).
%% API
-export([start_link/0,display/1,callDisplay/2]).
start_link()->
Pid=spawn(mytest,display,["Hello"]),
Pid.
display(Val) ->
io:format("It started: ~p",[Val]),
NextVal=
receive
{call,Msg}->
NewVal=Val++" "++Msg++" ",
NewVal;
stop->
true
end,
display(NextVal).
callDisplay(Pid,Val)->
Pid!{call,Val}.
Start it
Pid=mytest:start_link().
Two process are calling it in the same time
P1=spawn(mytest,callDisplay,[Pid,"Walter"]),
P2=spawn(mytest,callDisplay,[Pid,"Dave"]).
I hope it can add "Walter", "Dave" one by one like "Hello Walter Dave", however, when there're too many of them running together, some Names(Walter, Dave, etc) will be override.
Because when P1, P2 started the same time, Val both are "Hello". P1 add "Walter" to become "Hello Walter", P2 add "Dave" to become "Hello Dave". P1 saved it firstly to NextVal as "Hello Walter", then P2 saved it to NextVal as "Hello Dave", so result will be "Hello Dave". "Hello Walter" is replaced by "Hello Dave", and "Walter" lost forever.
Is there any way I can lock "Val", so when we add "Walter", "Dave" will waiting till Value setting is done?
Even though it's an old question but it's worth explaining.
From what you said and if I'm correct,
you expect to see
"Hello Walter", and "Hello Dave". However, you're seeing successive names been appended to the former as, "Hello Walter Dave.."
This behavior is normal and to see that let look briefly at Erlang memory model. Erlang process memory is divided into three main parts:
Process Control Block(PCB):
This hold the process pid, registered name,table,states and pointers to messages in the it's queue.
Stack:
This hold function parameters, local variables and function return address.
Private Heap: This hold incoming message compound data like tuple, list and binary(not larger than 64 bytes).
All data in these memory belong to and are private to the owning process.
Stage1:
When Pid=spawn(mytest,display,["Hello"]) is called, the server process is created, then the display function with "Hello" passed as argument is called. Since display/1 is executed in the serve process, the "Hello" argument lives in the server's process stack. Execution of display/1 continues until it reaches the receive clause then block and await message matching your format.
Stage 2:
Now P1 starts, it executes ServerPid ! {call, "Walter"}, then P2 executes ServerPid ! {call, "Dave"}. In both cases, erlang makes a copy of the message and send it to the server's process mailbox (Private Heap). This copied message in the mailbox belongs to the server process not the client's.
Now, when {call, "Walter"} is matched, Msg get bound to "Walter".
From stage1, we know Val is bounded to "Hello", Newval then get bounded to "Val ++ " " ++ Msg" = "Hello Walter".
At this point, P2's message, {call, "Dave"}, is still in the server's mailbox awaiting the next receive clause which will happen in the next recursive call to display/1. NextVal get bound to NewVal and the recursive call to dispaly/1 with "Hello Walter" passed as argument is made. This gives the first print "Hello Walter " which now also lives in the server's process stack.
Now when the receive clause is reach again, P2's message {call, "Dave"} is matched.
Now NewVal and NextVal get bound to "Hello Walter" ++ " " ++ "Dave" = "Hello Walter Dave". This get passed as argument to display/1 as the new Val to print Hello Walter Dave. In a nutshell, this variable is updated on every server loop. It serves the same purpose as the State term in gen_server behavior. In your case, successive client calls just appends the message to this serve state variable. Now to your question,
Is there any way I can lock Val, so when we add "Walter", "Dave" will waiting till Value setting is done?
No. Not by locking. Erlang does not work this way.
There are no process locking constructs as it does not need one.
Data(Variables) are always immutable and private(except large binaries which stays in the Shared Heap) to the process that created it.
Also, it's not the actual message you used in the Pid ! Msg construct that is process by the receiving process. It's it copy. The Val parameter in yourdisplay/1 function is private and belongs to the server process because it lives in it stack memory as every call to display/1 is made by the server process itself. So there is no way any other process can lock not even see that variable.
Yes. By sequential message processing
This is exactly what the server process is doing. Polling one message a time from it queue. When {call, "Walter"} was taken, {call, "Dave"} was waiting in the queue. The reason why you see unexpected greeting is because the you change the server state, the display/1 parameter for the next display/1 call which process {call, "Dave"}
I am working on my first project with Cobol Sort VSAM files. I ran into a keyword RELEASE.
The way the book read that I have is the "The release statement transfers records from the INPUT PROCEDURE to the input Phase of the sort operation.
My Question is: That takes what ever I have in my Sort-Rec (or whatever I called it) and sends it directly into the OUTPUT PROCEDURE part of my SORT?
Seems confusing to me here.
Cobol Code:
SORT SORT-FILE ASCENDING KEY SORT-PROVIDER
INPUT PROCEDURE IS PROC-THE-REC THRU PTR-X
OUTPUT PROCEDURE IS WRITE-THE-RPT THRU WTR-X.
MOVE CC-CERT-NO TO SAVE-CERT-NO.
MOVE CC-CERT-STATUS TO SAVE-CERT-STATUS.
MOVE CC-CERT-BEGIN-DATE TO SAVE-CERT-BEGIN-DATE.
MOVE CC-CERT-END-DATE TO SAVE-CERT-END-DATE.
MOVE CC-CERT-FUNDING TO SAVE-CERT-FUNDING.
MOVE CC-PROV-NUMB TO SAVE-PROV-NUMB.
MOVE CC-PROV-RES-CNTY TO SAVE-PROV-RES-CNTY.
MOVE CC-PROV-TYPE TO SAVE-PROV-TYPE.
MOVE CC-WORKER-USERID TO SAVE-WORKER-USERID.
MOVE CC-WORKER-NAME TO SAVE-WORKER-NAME.
RELEASE SORT-REC.
Following from Bill,
When using a sort in Cobol is a bit like having two or three separate programs in the one program.
Pre-Sort (PROC-THE-REC in your case)
|
V
Sort
|
V
Post sort (WRITE-THE-RPT in your case)
The RELEASE statement "Writes" a record to the "Sort" step.
In Unix you could achieve the same thing by
writing 2 separate programs (Pre and post sort)
Replacing the Release with Writes
piping the output from the Pre-Sort to the sort.
On the mainframe you would use 3 JCL steps and temporary files.
On the mainframe, most sites I worked at discourage (ban) the use of the Cobol sort verb and you would write 2 programs and use the utility sort.
The release statement transfers records from the INPUT PROCEDURE to
the input Phase of the sort operation.
The input Phase of a sort is where SORT gets its data from, in this case.
COBOL Program
Loop-construct
Some COBOL code
Release
Next
The sort is actually an external program. In the case of the Mainframe,
it is the installed SORT product (usually DFSORT or SyncSort)
Input Phase of SORT
SORT
Output Phase of SORT
Another-Loop-construct
Some COBOL code
Return
Next
COBOL Program
Your input procedure will process, release, and then continue. When all data has been released, the sort will take place. The sorted records will be presented back to your program at the point of the RETURN statement you will have coded, and this will continue (return, stuff after return, another return, repeat until finished) until all the sorted file is processed (assuming that nothing goes wrong an you want to stop early).
normally, COBOL sort procedures are :
SORT SORTFILE ON SORT-ID, SORT-NAME, SORT-PHONE
INPUT PROCEDURE IS READ-IN
OUTPUT PROCEDURE IS PRINT-SORTED.
READ-IN SECTION.
loop:
READ INPUTFILE.
MOVE IN-ID TO SORT-ID.
MOVE IN-NAME TO SORT-NAME.
MOVE IN-PHONE TO SORT-PHONE.
RELEASE SORT-REC.
PRINT-SORTED SECTION.
loop:
RETURN SORT-REC.
DISPLAY "id#: " SORT-ID.
DISPLAY "Name: " SORT-NAME.
DISPLAY "Phone: " SORT-PHONE.
An INPUT PROCEDURE supplies records to the sort process by writing them to the work file declared in the SORT's SD entry. But to write the records to the work file a special verb - the RELEASE verb is used.
An operational template for an INPUT PROCEDURE, which gets records from and input file and RELEASEs them to the work file, is shown below.
OPEN INPUT InFileName
READ InFileName
PERFORM UNTIL TerminatingCondition
Process input record to create SDWorkRec
RELEASE SDWorkRec
READ InFileName
END-PERFORM
CLOSE InFileName
For further details on the SORT see my tutorial at http://www.csis.ul.ie/cobol/course/SortMerge.htm
Can someone explain the structure of a Pid in Erlang?
Pids looks like this: <A.B.C>, e.g. <0.30.0> , but I would like to know what is the meaning of these three "bits": A, B and C.
A seems to be always 0 on a local node, but this value changes when the Pid's owner is located on another node.
Is it possible to directly send a message on a remote node using only the Pid? Something like that: <4568.30.0> ! Message, without having to explicitly specify the name of the registered process and the node name ( {proc_name, Node} ! Message)?
Printed process ids < A.B.C > are composed of 6:
A, the node number (0 is the local
node, an arbitrary number for a remote node)
B, the first 15 bits of the process number (an index into the process table) 7
C, bits 16-18 of the process number (the same process number as B) 7
Internally, the process number is 28 bits wide on the 32 bit emulator. The odd definition of B and C comes from R9B and earlier versions of Erlang in which B was a 15bit process ID and C was a wrap counter incremented when the max process ID was reached and lower IDs were reused.
In the erlang distribution PIDs are a little larger as they include the node atom as well as the other information. (Distributed PID format)
When an internal PID is sent from one node to the other, it's automatically converted to the external/distributed PID form, so what might be <0.10.0> (inet_db) on one node might end up as <2265.10.0> when sent to another node. You can just send to these PIDs as normal.
% get the PID of the user server on OtherNode
RemoteUser = rpc:call(OtherNode, erlang,whereis,[user]),
true = is_pid(RemoteUser),
% send message to remote PID
RemoteUser ! ignore_this,
% print "Hello from <nodename>\n" on the remote node's console.
io:format(RemoteUser, "Hello from ~p~n", [node()]).
For more information see: Internal PID structure,
Node creation information,
Node creation counter interaction with EPMD
If I remember this correctly the format is <nodeid,serial,creation>.
0 is current node much like a computer always has the hostname "localhost" to refer to itself. This is by old memory so it might not be 100% correct tough.
But yes. You could build the pid with list_to_pid/1 for example.
PidString = "<0.39.0>",
list_to_pid(PidString) ! message.
Of course. You just use whatever method you need to use to build your PidString. Probably write a function that generates it and use that instead of PidString like such:
list_to_pid( make_pid_from_term({proc_name, Node}) ) ! message
Process id < A.B.C > is composed of:
A, node id which is not arbitrary but the internal index for that node in dist_entry. (It is actually the atom slot integer for the node name.)
B, process index which refers to the internal index in the proctab, (0 -> MAXPROCS).
C, Serial which increases every time MAXPROCS has been reached.
The creation tag of 2 bits is not displayed in the pid but is used internally and increases every time the node restarts.
The PID refers to a process and a node table. So you can only send a message directly to a PID if it is known in the node from which you do the call.
It is possible that this will work if the node you do the call from already knows about the node on which the process is running.
Apart from what others have said, you may find this simple experiment useful to understand what is going on internally:
1> node().
nonode#nohost
2> term_to_binary(node()).
<<131,100,0,13,110,111,110,111,100,101,64,110,111,104,111,
115,116>>
3> self().
<0.32.0>
4> term_to_binary(self()).
<<131,103,100,0,13,110,111,110,111,100,101,64,110,111,104,
111,115,116,0,0,0,32,0,0,0,0,0>>
So, you can se that the node name is internally stored in the pid. More info in this section of Learn You Some Erlang.