Passing a variable by address lazarus / 21-General ---------------------------------------------------------------------- MarkMLl · 2021-04-30 15:13 My understanding is that if a procedure or function parameter is to both convey information on entry and potentially be modified on exit, then it must be declared as var. My understanding is also that if a procedure or function parameter is to convey information on entry but will not be modified, then it should be declared as const. What is the correct declaration of a parameter which will not be changed by anything the function does, but may be changed asynchronously by a unix-style signal? C/C++ would call it volatile, and the statements above would imply that it should be const, but would this guarantee that even a simple variable would be passed by address rather than being copied? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i (* Wait until we can be reasonably confident that we're not still in the middle  of an input line.*)procedure WaitInputGap(handle: TSerialHandle; var termFlag: boolean); var  avail: integer; begin  SerFlushInput(handle);  repeat    if fpIoctl(handle, FIONREAD, @avail) <> 0 then      break;    Sleep(50);    SerFlushInput(handle)  until (avail = 0) or termFlagend { WaitInputGap } ;  As a subsidiary question and noting that I think this was discussed a few weeks ago, is it possible for a program's main unit to expose the termination flag as a variable or (better) a function or (best) a read-only unit property? MarkMLl ---------------------------------------------------------------------- egsuh · 2021-04-30 15:37 I'm not sure I understand you correctly. But can't pointers do what you want? In the following example, if anything asynchronously change the content of PInt^, then it will be reflected within the procedure DoSomething.  Haven't checked syntax nor tested. Even not sure "pointer to interger" is correct syntax. But I know that there are similar declarations. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var     PInt: pointer to integer;  procedure DoSomething (apint: pointer to integer);begin     ...     if apint^ = 0 then ...  end;  begin      ....      New(PInt);      DoSomething (PInt);      .... end; ---------------------------------------------------------------------- MarkMLl · 2021-04-30 15:49 Quote from: egsuh on April 30, 2021, 05:37:40 pmI'm not sure I understand you correctly. But can't pointers do what you want? Yes, but a pointer is synonymous with a var (in fact somewhat less safe, since unless protected by const it can itself be changed) so good practice would suggest that something stronger be used where the function is not expected/allowed to change the parameter. Perhaps a constref? Would this guarantee appropriate behaviour and are there any gotchas? MarkMLl ---------------------------------------------------------------------- egsuh · 2021-04-30 16:04 I don't think const would do. Value will be passed with const parameter. We may think of a read-only property. The field itself is not accessible from the procedure, but it can be changed directly by other part of program. For example a variable is defined in unit A, property is defined in unit B which uses A, and your procedure is defined within unit C, which uses B but not A. ---------------------------------------------------------------------- lucamar · 2021-04-30 16:39 Quote from: MarkMLl on April 30, 2021, 05:49:03 pmPerhaps a constref? Would this guarantee appropriate behaviour and are there any gotchas? constref does indeed almost what you want: it guarantees that the parameter will be passed by reference. Only gotcha  I can think of is that it's not exactly like volatile so depending on target, optimization level, etc. it might not behave consistently: e.g. the value might be kept in a register after some operation and be used from there instead of re-reading it, etc. ---------------------------------------------------------------------- MarkMLl · 2021-04-30 17:22 Quote from: lucamar on April 30, 2021, 06:39:56 pmconstref does indeed almost what you want: it guarantees that the parameter will be passed by reference. Only gotcha  I can think of is that it's not exactly like volatile so depending on target, optimization level, etc. it might not behave consistently: e.g. the value might be kept in a register after some operation and be used from there instead of re- reading it, etc. Thanks very much. I'll make the tentative assumption that since there's typically an OS call or some string manipulation in the loop the underlying pointer will get dereferenced regularly. This might actually be a good place for a macro: expand as constref or var as required. Under the circumstances I think I'd prefer having the termination flag be some sort of main-unit global, but the important thing is to have something that works. MarkMLl ---------------------------------------------------------------------- alpine · 2021-04-30 18:11 Quote from: MarkMLl on April 30, 2021, 05:13:43 pmMy understanding is that if a procedure or function parameter is to both convey information on entry and potentially be modified on exit, then it must be declared as var. My understanding is also that if a procedure or function parameter is to convey information on entry but will not be modified, then it should be declared as const. What is the correct declaration of a parameter which will not be changed by anything the function does, but may be changed asynchronously by a unix-style signal? C/C++ would call it volatile, and the statements above would imply that it should be const, but would this guarantee that even a simple variable would be passed by address rather than being copied? *snip* AFAIK 'volatile' modifier in C/C++ doesn't relate to parameter passing but to hint the compiler that the variable ca be suddenly changed by some external signal, interrupt handler or thread. In such a case the compiler shouldn't optimize it by putting in register or so. Besides, in FPC there has 'interrupt' modifier for routines and also 'bare' ports - AVR. IMHO that (volatile variables) are becoming an important subject for embedded targets. It would probably be good if someone could shed some light on the issue. Anyone? Regards, ---------------------------------------------------------------------- MarkMLl · 2021-04-30 19:42 Quote from: y.ivanov on April 30, 2021, 08:11:14 pmAFAIK 'volatile' modifier in C/C++ doesn't relate to parameter passing but to hint the compiler that the variable ca be suddenly changed by some external signal, interrupt handler or thread. In such a case the compiler shouldn't optimize it by putting in register or so. An explicit "shouldn't optimise by"... yes, good point. I've ended up putting this near the top of the unit and using where appropriate: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$macro on}{$define ROREF:= constref }             (* Use constref or if necessary var     *)[code] By and large I'm strict on checking correct operation of anything questionable, but I suspect that correct operation of this one wouldn't be a particularly easy thing to verify... I suppose that a program could send a SIGINT to itself and check that a flag had changed as soon as the syscall returned. I probably won't bother in this particular case, since the parameter is /only/ being used to ensure that the program terminates rapidly and in good order, and it's not going anywhere near a customer. TBH I think FPC should have volatile and static modifiers... and I don't give a damn whether they're too "C-like" for some people >:-| MarkMLl ---------------------------------------------------------------------- ccrause · 2021-04-30 20:13 There is a volatile intrinsic in trunk.  Marking a particular access as volatile should force the compiler to load/store as appropriate. ---------------------------------------------------------------------- MarkMLl · 2021-04-30 20:45 Quote from: ccrause on April 30, 2021, 10:13:18 pmThere is a volatile intrinsic in trunk.  Marking a particular access as volatile should force the compiler to load/store as appropriate. Thanks very much, noted. So presumably that could be used with constref to both prevent attempted modification by a function and ensure that the function was attentive to external modification. Since it's an intrinsic I presume that the only way of checking for its existence is by having conditional compilation look carefully at the compiler version number. MarkMLl ---------------------------------------------------------------------- alpine · 2021-05-01 09:59 Digging further in that 'volatile' thing I rather found it extremely vague and mistreated by the compilers. The only reasonable rationale behind it would be for I/O mapping and the side effects on the peripherals, something like: *ttyport = a[i++]; cited: https://lwn.net/Articles/233482/ and also https://stackoverflow.com/questions/38235112/why-is-a-volatile-local- variable-optimised-differently-from-a-volatile-argument https://www.cs.utah.edu/~regehr/papers/emsoft08-preprint.pdf http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf Thus, I agreed, the volatile intrinsic is much more appropriate than the storage attribute, moreover, it won't introduce ambiguity between volatiles, refs to volatiles, pointers to volatiles, etc. @MarkMLl IMHO, doing simple variable checks for graceful termination should be perfectly OK and without any concern, since it will probably reside in separate subroutine and won't be 'swallowed' through CSE or whatever optimization cleverness... At least, as long as the following continues to work, everything should be fine Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TMyThread.Execute;begin  while not Terminated do ...end; ---------------------------------------------------------------------- jamie · 2021-05-01 10:27 Quote from: MarkMLl on April 30, 2021, 05:13:43 pmMy understanding is that if a procedure or function parameter is to both convey information on entry and potentially be modified on exit, then it must be declared as var. My understanding is also that if a procedure or function parameter is to convey information on entry but will not be modified, then it should be declared as const. What is the correct declaration of a parameter which will not be changed by anything the function does, but may be changed asynchronously by a unix-style signal? C/C++ would call it volatile, and the statements above would imply that it should be const, but would this guarantee that even a simple variable would be passed by address rather than being copied? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i (* Wait until we can be reasonably confident that we're not still in the middle  of an input line.*)procedure WaitInputGap(handle: TSerialHandle; var termFlag: boolean); var  avail: integer; begin  SerFlushInput(handle);  repeat    if fpIoctl(handle, FIONREAD, @avail) <> 0 then      break;    Sleep(50);    SerFlushInput(handle)  until (avail = 0) or termFlagend { WaitInputGap } ;  As a subsidiary question and noting that I think this was discussed a few weeks ago, is it possible for a program's main unit to expose the termination flag as a variable or (better) a function or (best) a read-only unit property? MarkMLl if I understand your post...  You are concerned about a variable changing while you are handling the last value of it within a function from the parameter entry ?  if that is the case, you don't want to use CONST, CONSTREF, Var or OUT because CONST will free for the compiler to optimize the code so it could be what ever the compiler see's fit when it constructed the function.    CONSTREF ensures that it's always a pointer (VAR) referenced but you still can only read from it.  and of course VAR and OUT is a pointer reference.  If you want a value that remains constant within the function then just pass it directly with NO CONST, VAR or OUT.. All simply types will be Register or stacked pushed and there for remain constant within your function and you are free to change it of course  If you are in a case where you need a locked value and also need to write back then you need to pass it as two parameters, one as I have said to prevent change and the other as a VAR so  you can write back in C/C++ the Volatile is only a compiler optimizer to instruct the compiler that the value may change so it needs to may a choice about how it references it, from a Register loaded once or always referenced from the original source. This depends on the code, for example a control loop that must not have its value changed during the intrinsic of the loop etc.. ---------------------------------------------------------------------- alpine · 2021-05-01 10:46 Wouldn't it be better then: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type   TTerminationFunc = function: Boolean; function IsTerminated: Boolean;begin    Result := your_termination_flag;end; procedure WaitInputGap(handle: TSerialHandle; IsTerm: TTerminationFunc);begin  ...  until (avail = 0) or IsTermend;   ...  WaitInputGap(AHandle, @IsTerminated);  ... ---------------------------------------------------------------------- MarkMLl · 2021-05-01 10:49 @Jamie, you have got TOTALLY the wrong end of the stick. QuoteWhat is the correct declaration of a parameter which will not be changed by anything the function does, but may be changed asynchronously by a unix-style signal? ...plus obviously look at the example WHICH YOU QUOTED. The whole point is that a termination signal signal detected in a unix-style console program SHOULD be picked up promptly and break any loops. MarkMLl ---------------------------------------------------------------------- MarkMLl · 2021-05-01 10:53 Quote from: y.ivanov on May 01, 2021, 12:46:17 pmWouldn't it be better then: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type   TTerminationFunc = function: Boolean; function IsTerminated: Boolean;begin    Result := your_termination_flag;end; procedure WaitInputGap(handle: TSerialHandle; IsTerm: TTerminationFunc);begin  ...  until (avail = 0) or IsTermend;   ...  WaitInputGap(AHandle, @IsTerminated);  ...   Perhaps, but it's just layering complexity where it's not really needed. The best- IMO- solution would be a read-only export of the termination flag from the main unit. Or possibly moving it to the utility unit in which most of its usage occurs, but I find that unnatural since a signal handler so clearly pertains to the main program. MarkMLl ---------------------------------------------------------------------- alpine · 2021-05-01 11:02 Quote from: MarkMLl on May 01, 2021, 12:53:41 pmPerhaps, but it's just layering complexity where it's not really needed. The best- IMO- solution would be a read-only export of the termination flag from the main unit. Or possibly moving it to the utility unit in which most of its usage occurs, but I find that unnatural since a signal handler so clearly pertains to the main program. MarkMLl My point was that it will satisfy both requirements: It provides read-only semantics for your flag, at least in the scope of WaitInputGap()It will not become a meat for the optimizer ---------------------------------------------------------------------- MarkMLl · 2021-05-01 11:21 Quote from: y.ivanov on May 01, 2021, 01:02:55 pmMy point was that it will satisfy both requirements: It provides read-only semantics for your flag, at least in the scope of WaitInputGap()It will not become a meat for the optimizer True, good points. MarkMLl ---------------------------------------------------------------------- PascalDragon · 2021-05-01 11:47 Quote from: MarkMLl on April 30, 2021, 10:45:33 pmQuote from: ccrause on April 30, 2021, 10:13:18 pmThere is a volatile intrinsic in trunk.  Marking a particular access as volatile should force the compiler to load/store as appropriate. Thanks very much, noted. So presumably that could be used with constref to both prevent attempted modification by a function and ensure that the function was attentive to external modification. No. With const or constref you give the compiler the guarantee that the value won't be changed behind its back cause it will then optimize accordingly (e.g. “cache” it in a register). Best is to use the Volatile intrinsic in trunk together with the var modifier which allows for a more flexible control than a volatile modifier would. In 3.2.0 the best you can do is to use a global variable, because these are always volatile (this changes with 3.3.1 due to the addition of the LLVM backend). For var parameters there is no such guarantee. Quote from: MarkMLl on April 30, 2021, 10:45:33 pmSince it's an intrinsic I presume that the only way of checking for its existence is by having conditional compilation look carefully at the compiler version number. You can use Declared conditional compilation: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program tvolatile; begin  {$if declared(volatile)}    Writeln('Has volatile'); // 3.3.1 will print this  {$else}    Writeln('Doesn''t have volatile'); // 3.2.0 will print this  {$endif}end. Caveat: this will result in a false positive if there is any other Volatile identifier in scope, because you can't use System.Volatile (yet). ---------------------------------------------------------------------- MarkMLl · 2021-05-01 15:04 Quote from: PascalDragon on May 01, 2021, 01:47:54 pmNo. With const or constref you give the compiler the guarantee that the value won't be changed behind its back cause it will then optimize accordingly (e.g. “cache” it in a register). Best is to use the Volatile intrinsic in trunk together with the var modifier which allows for a more flexible control than a volatile modifier would. In 3.2.0 the best you can do is to use a global variable, because these are always volatile (this changes with 3.3.1 due to the addition of the LLVM backend). For var parameters there is no such guarantee. Ah. So that more or less takes me back to my initial position: guarantee a pass-by-address using var, with no way of telling the compiler that the called function must not attempt to change the parameter. QuoteYou can use Declared conditional compilation: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program tvolatile; begin  {$if declared(volatile)}    Writeln('Has volatile'); // 3.3.1 will print this  {$else}    Writeln('Doesn''t have volatile'); // 3.2.0 will print this  {$endif}end. Caveat: this will result in a false positive if there is any other Volatile identifier in scope, because you can't use System.Volatile (yet). So is it really an intrinsic, i.e. implemented entirely by the compiler, or is it a routine in System? I'd assumed that intrinsics weren't in any of the standard libraries so weren't picked up by declared(). I've currently got Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$macro on}{$define ROREF_:= constref    }         (* Use constref or if necessary var     *){$if FPC_FULLVERSION > 030400 }         (* Test requires FPC 2.2.4 minimum      *){$define VOLATILE_:=volatile  }       (* Not supported until FPC 3.4ish       *){$else                      }{$define VOLATILE_:=          }{$endif                       }  but will change bearing in mind your comment about constref. MarkMLl ---------------------------------------------------------------------- jamie · 2021-05-01 15:27 I don't get you..  if you don't use VAR, out or even  a pointer, you can do what ever you wish with it in the function, its not going to change the source. But if you want to see external action taking place and not allow your code to change it then use the CONSTREF. But if you can't manage our own code In a function then I don't know what to say at this point. ---------------------------------------------------------------------- PascalDragon · 2021-05-02 12:14 Quote from: MarkMLl on May 01, 2021, 05:04:09 pmQuoteYou can use Declared conditional compilation: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program tvolatile; begin  {$if declared(volatile)}    Writeln('Has volatile'); // 3.3.1 will print this  {$else}    Writeln('Doesn''t have volatile'); // 3.2.0 will print this  {$endif}end. Caveat: this will result in a false positive if there is any other Volatile identifier in scope, because you can't use System.Volatile (yet). So is it really an intrinsic, i.e. implemented entirely by the compiler, or is it a routine in System? I'd assumed that intrinsics weren't in any of the standard libraries so weren't picked up by declared(). Intrinsics are always part of unit System. You can use the same trick with Writeln for example. Quote from: MarkMLl on May 01, 2021, 05:04:09 pmI've currently got Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$macro on}{$define ROREF_:= constref    }         (* Use constref or if necessary var     *){$if FPC_FULLVERSION > 030400 }         (* Test requires FPC 2.2.4 minimum      *){$define VOLATILE_:=volatile  }       (* Not supported until FPC 3.4ish       *){$else                      }{$define VOLATILE_:=          }{$endif                       }  but will change bearing in mind your comment about constref. Even if you should wait for the release of 3.4 you should check with >= instead of >. But you can also use FPC_FULLVERSION >= 030301, because we only consider the latest revision of FPC the valid one. Quote from: jamie on May 01, 2021, 05:27:31 pmI don't get you..  if you don't use VAR, out or even  a pointer, you can do what ever you wish with it in the function, its not going to change the source. But if you want to see external action taking place and not allow your code to change it then use the CONSTREF. But if you can't manage our own code In a function then I don't know what to say at this point. He wants to pass a reference to a variable that he'll modify in a signal handler (e.g. SIGINT) to signal his code something (e.g. abort). Thus the compiler must not optimize accesses to that reference (e.g. by caching its value in a register). The compiler however won't guarantee to abstain from optimizations without the new Volatile intrinsic. The only exception here are global variables (but not parameters that might point to a global variable, cause from the point of view of the callee they aren't global anymore). ---------------------------------------------------------------------- MarkMLl · 2021-05-02 13:45 Quote from: PascalDragon on May 02, 2021, 02:14:18 pmIntrinsics are always part of unit System. You can use the same trick with Writeln for example. ... Even if you should wait for the release of 3.4 you should check with >= instead of >. But you can also use FPC_FULLVERSION >= 030301, because we only consider the latest revision of FPC the valid one. Thanks for those, noted. The notes somebody cited earlier specified "trunk" without any number, so I was being careful with my versioning. MarkMLl ---------------------------------------------------------------------- PascalDragon · 2021-05-03 07:10 Quote from: MarkMLl on May 02, 2021, 03:45:58 pmQuote from: PascalDragon on May 02, 2021, 02:14:18 pmIntrinsics are always part of unit System. You can use the same trick with Writeln for example. ... Even if you should wait for the release of 3.4 you should check with >= instead of >. But you can also use FPC_FULLVERSION >= 030301, because we only consider the latest revision of FPC the valid one. hanks for those, noted. The notes somebody cited earlier specified "trunk" without any number, so I was being careful with my versioning. Development versions of trunk always have a odd number at the minor part and a 1 at the release. So 2.7.1, 3.1.1, 3.3.1 and the future 3.5.1 are all development versions. For Fixes versions they have an odd number at the end: 2.6.5, 3.0.1, 3.2.1 and the future 3.2.3. ---------------------------------------------------------------------- MarkMLl · 2021-05-03 07:44 Quote from: PascalDragon on May 03, 2021, 09:10:51 amDevelopment versions of trunk always have a odd number at the minor part and a 1 at the release. So 2.7.1, 3.1.1, 3.3.1 and the future 3.5.1 are all development versions. For Fixes versions they have an odd number at the end: 2.6.5, 3.0.1, 3.2.1 and the future 3.2.3. SOP, although I don't know who introduced it (possibly the Linux kernel). But since the description of new features in trunk didn't identify its own tentative version but said that the previous one was 3.2, I selected 3.4 as the safe choice. MarkMLl ---------------------------------------------------------------------- nanobit · 2021-05-03 08:57 Quote from: MarkMLl on April 30, 2021, 05:13:43 pmWhat is the correct declaration of a parameter which will not be changed by anything the function does, but may be changed asynchronously by a unix-style signal? MarkMLl IMO, in your specific example (...; var termFlag: boolean) you can also use: (... ; const pTermFlag: PBoolean); and "until (avail = 0) or (pTermFlag^)" The optimizer should see only the variable pTermFlag, and he should not touch (PTermFlag^), which is like a blackbox: (...; const pTermFlag: pointer) and PBoolean(pTermFlag)^ Disclaimer: I don't know the specifics of the FPC optimizer. Better use a function as loop terminator. ---------------------------------------------------------------------- zamronypj · 2021-05-03 09:41 This does not answer question but maybe you can consider self-pipe trick. https://cr.yp.to/docs/selfpipe.html 1) Create pipe, fpPipe() make it non blocking 2) Establish signal handler. In signal handler, write a byte to pipe output when receive SIGINT 3) In code which waiting for termination (in this case WaitInputGap()), check for pipe input readability (fpSelect()). If readable it means SIGINT received.