I'm trying the newly implemented try/catch statements which are available since TwinCAT 4024.0. However, I'm getting the following error when compiling:
The codegenerator for the current device does not support structured exception handling.
Example code (source):
FUNCTION F_Calc : LREAL
VAR_INPUT
pData : POINTER TO ARRAY [0..9] OF LREAL;
nElementA : INT;
nElementB : INT;
END_VAR
VAR
exc : __SYSTEM.ExceptionCode;
END_VAR
__TRY
F_Calc := pData^[nElementA] / pData^[nElementB];
__CATCH (exc)
IF (exc = __SYSTEM.ExceptionCode.RTSEXCPT_ARRAYBOUNDS) THEN
F_Calc := -1;
ELSIF ((exc = __SYSTEM.ExceptionCode.RTSEXCPT_FPU_DIVIDEBYZERO) OR
(exc = __SYSTEM.ExceptionCode.RTSEXCPT_DIVIDEBYZERO)) THEN
F_Calc := -2;
ELSIF (exc = __SYSTEM.ExceptionCode.RTSEXCPT_ACCESS_VIOLATION) THEN
F_Calc := -3;
ELSE
F_Calc := -4;
END_IF
__ENDTRY
Turns out the try catch statements are not supported for 64-bit systems yet. This is also mentioned in this article.
From the comment section of this article on why it doesn't work on 64-bit yet:
In the case of an exception, quite a lot happens internally. For
example, the stack must be cleaned. Especially with deeply nested
method calls, this can mean a lot of work. I suspect that memory
management is structured under 32 bit differently than under 64 bits.
However, I assume that this will be implemented for 64 bit systems in
a later build.
Related
I'm generating random files programmatically in a directory, at least temporaryFilesTotalSize worth of random data (a bit more, who cares).
Here's my code:
var files []string
for size := int64(0); size < temporaryFilesTotalSize; {
fileName := random.HexString(12)
filePath := dir + "/" + fileName
file, err := os.Create(filePath)
if err != nil {
return nil, err
}
size += rand.Int63n(1 << 32) // random dimension up to 4GB
raw := make([]byte, size)
_, err := rand.Read(raw)
if err != nil {
panic(err)
}
file.Write(raw)
file.Close()
files = append(files, filePath)
}
Is there any way I can avoid that raw := make([]byte, size) allocation in the for loop?
Ideally I'd like to keep a slice on the heap and only grow if a bigger size is required. Any way to do this efficiently?
First of all you should know that generating random data and writing that to disk is at least an order of magnitude slower than allocating a contiguous memory for buffer. This definitely falls under the "premature optimization" category. Eliminating the creation of the buffer inside the iteration will not make your code noticeably faster.
Reusing the buffer
But to reuse the buffer, move it outside of the loop, create the biggest needed buffer, and slice it in each iteration to the needed size. It's OK to do this, because we'll overwrite the whole part we need with random data.
Note that I somewhat changed the size generation (likely an error in your code as you always increase the generated temporary files, since you use the size accumulated size for new ones).
Also note that writing a file with contents prepared in a []byte is easiest done using a single call to os.WriteFile().
Something like this:
bigRaw := make([]byte, 1 << 32)
for totalSize := int64(0); ; {
size := rand.Int63n(1 << 32) // random dimension up to 4GB
totalSize += size
if totalSize >= temporaryFilesTotalSize {
break
}
raw := bigRaw[:size]
rand.Read(raw) // It's documented that rand.Read() always returns nil error
filePath := filepath.Join(dir, random.HexString(12))
if err := os.WriteFile(filePath, raw, 0666); err != nil {
panic(err)
}
files = append(files, filePath)
}
Solving the task without an intermediate buffer
Since you are writing big files (GBs), allocating that big buffer is not a good idea: running the app will require GBs of RAM! We could improve it with an inner loop to use smaller buffers until we write the expected size, which solves the big memory issue, but increases complexity. Luckily for us, we can solve the task without any buffers, and even with decreased complexity!
We should somehow "channel" the random data from a rand.Rand to the file directly, something similar what io.Copy() does. Note that rand.Rand implements io.Reader, and os.File implements io.ReaderFrom, which suggests we could simply pass a rand.Rand to file.ReadFrom(), and the file itself would get the data directly from rand.Rand that will be written.
This sounds good, but the ReadFrom() reads data from the given reader until EOF or error. Neither will ever happen if we pass rand.Rand. And we do know how many bytes we want to be read and written: size.
To our "rescue" comes io.LimitReader(): we pass an io.Reader and a size to it, and the returned reader will supply no more than the given number of bytes, and after that will report EOF.
Note that creating our own rand.Rand will also be faster as the source we pass to it will be created using rand.NewSource() which returns an "unsynchronized" source (not safe for concurrent use) which in turn will be faster! The source used by the default/global rand.Rand is synchronized (and so safe for concurrent use–but is slower).
Perfect! Let's see this in action:
r := rand.New(rand.NewSource(time.Now().Unix()))
for totalSize := int64(0); ; {
size := r.Int63n(1 << 32)
totalSize += size
if totalSize >= temporaryFilesTotalSize {
break
}
filePath := filepath.Join(dir, random.HexString(12))
file, err := os.Create(filePath)
if err != nil {
return nil, err
}
if _, err := file.ReadFrom(io.LimitReader(r, fsize)); err != nil {
panic(err)
}
if err = file.Close(); err != nil {
panic(err)
}
files = append(files, filePath)
}
Note that if os.File would not implement io.ReaderFrom, we could still use io.Copy(), providing the file as the destination, and a limited reader (used above) as the source.
Final note: closing the file (or any resource) is best done using defer, so it'll get called no matter what. Using defer in a loop is a bit tricky though, as deferred functions run at the end of the enclosing function, and not at the end of the loop's iteration. So you may wrap it in a function. For details, see `defer` in the loop - what will be better?
I have implemented the levigo wrapper in my project so I can use LevelDB. The declaration is fairly boilerplate, like so:
func NewLeveldbStorage(dbPath string) *leveldbStorage {
opts := levigo.NewOptions()
opts.SetCache(levigo.NewLRUCache(3<<30))
opts.SetCreateIfMissing(true)
log.Debugf("Entering Open")
db, err := levigo.Open(dbPath, opts); if err != nil {
log.Fatal("BOOM %v", err)
}
log.Debugf("Finished calling open")
opts.Close()
return &leveldbStorage{db:db}
}
Here is the struct returned:
type leveldbStorage struct {
db *levigo.DB
}
I then made a few simple GET and STORE commands on the struct that essentially just use s.db.Get and s.db.Put. This works fine in my tests, but when I run the following benchmark:
func BenchmarkLeviDbGet(b *testing.B) {
s := storage.NewLeveldbStorage("/path/to/db")
value := "value"
uid,_ := s.Store(value)
b.ResetTimer()
for i := 0; i < b.N; i++ {
s.Get(uid)
}
This benchmark, when run, returns:
2014/10/12 21:17:09 BOOM %vIO error: lock /path/to/db/LOCK: already held by process
Is there an appropriate way to use levigo/leveldb to enable multithreaded reading? What about writing? I would not be surprised if multithreaded writing is not possible, but multithreaded reading seems like it should be. What am I doing wrong here?
You either need to close the database file or use a global instance to it, you can't open the file multiple times, you can however access the same instance from multiple goroutines.
Oops, there was one thing I forgot when I made this answer, and it's something that I'm both not quite sure on myself and that I can't seem to find information for on MSDN and Google and the Stack Overflow search.
There are a number of places in the Windows API where you use a negative number, or a number too large to fit in a signed integer; for instance, CW_USEDEFAULT, INVALID_HANDLE_VALUE, GWLP_USERDATA, and so on. In the world of C, everything is all fine and dandy: the language's integer promotion rules come to the rescue.
But in Go, I have to pass all my arguments to functions as uintptr (which is equivalent to C's uintptr_t). The return value from the function is also returned this way, and then I will need to compare. Go doesn't allow integer promotion, and it doesn't allow you to convert a signed constant expression into an unsigned one at compile-time.
Right now, I have a bit of a jerry-rig set up for handling these constants in my UI library. (Here's an example of what this solution looks like in action.) However, I'm not quite satisfied with this solution; it feels to me like it's assuming things about the ABI, and I want to be absolutely sure of what I'm doing.
So my question is: how are signed values handled when passing them to Windows API functions and how are they handled when returning?
All my constants are autogenerated (example output). The autogenerator uses a C ffi, which I'd rather not use for the main project since I can call the DLLs directly (this also makes cross-compilation easier at least for the rest of the year). If I could somehow leverage that, for instance by making everything into a C-side variable of the form
uintptr_t x_CONST_NAME = (uintptr_t) (CONST_NAME);
that would be helpful. But I can't do that without this answer.
Thanks!
Update
Someone on IRC put it differently (reformatted to avoid horizontal scrolling):
[19:13] <FraGag> basically, you're asking whether an int with a value of -1
will be returned as 0x00000000FFFFFFFF or as 0xFFFFFFFFFFFFFFFF
if an int is 4 bytes and an uintptr is 8 bytes
Basically this, but specifically for Windows API interop, for parameters passed in, and regardless of uintptr size.
#twotwotwo's comments to my question pointed me in the right direction. If Stack Overflow allowed marking comments as answers and having multiple answers marked, I'd do that.
tl;dr version: what I have now is correct after all.
I wrote a program (below) that simply dumped all the constants from package syscall and looked for constants that were negative, but not == -1 (as that would just be ^0). The standard file handles (STD_ERROR_HANDLE, STD_INPUT_HANDLE, and STD_OUTPUT_HANDLE) are (-12, -10, and -11, respectively). The code in package syscall passes these constants as the sole argument of getStdHandle(h int), which produces the required file handle for package os. getStdHandle() passes this int to an autogenerated function GetStdHandle(stdhandle int) that wraps a call to the GetStdHandle() system call. GetStdHandle() takes the int and merely converts it to uintptr for passing into syscall.Syscall(). Though no explanation is given in the autogenerator's source (mksyscall_windows.go), if this didn't work, neither would fmt.Println() =P
All of the above is identical on both windows/386 and windows/amd64; the only thing in a processor-specific file is GetStdHandle(), but the relevant code is identical.
My negConst() function is already doing the same thing, just more directly. As such, I can safely assume that it is correct.
Thanks!
// 4 june 2014
// based on code from 24 may 2014
package main
import (
"fmt"
"os"
"strings"
"go/token"
"go/ast"
"go/parser"
"code.google.com/p/go.tools/go/types"
_ "code.google.com/p/go.tools/go/gcimporter"
)
var arch string
func getPackage(path string) (typespkg *types.Package, pkginfo types.Info) {
var pkg *ast.Package
fileset := token.NewFileSet() // parser.ParseDir() actually writes to this; not sure why it doesn't return one instead
filter := func(i os.FileInfo) bool {
if strings.Contains(i.Name(), "_windows") &&
strings.Contains(i.Name(), "_" + arch) &&
strings.HasSuffix(i.Name(), ".go") {
return true
}
if i.Name() == "race.go" || // skip these
i.Name() == "flock.go" {
return false
}
return strings.HasSuffix(i.Name(), "_windows.go") ||
(!strings.Contains(i.Name(), "_"))
}
pkgs, err := parser.ParseDir(fileset, path, filter, parser.AllErrors)
if err != nil {
panic(err)
}
for k, _ := range pkgs { // get the sole key
if pkgs[k].Name == "syscall" {
pkg = pkgs[k]
break
}
}
if pkg == nil {
panic("package syscall not found")
}
// we can't pass pkg.Files directly to types.Check() because the former is a map and the latter is a slice
ff := make([]*ast.File, 0, len(pkg.Files))
for _, v := range pkg.Files {
ff = append(ff, v)
}
// if we don't make() each map, package types won't fill the structure
pkginfo.Defs = make(map[*ast.Ident]types.Object)
pkginfo.Scopes = make(map[ast.Node]*types.Scope)
typespkg, err = new(types.Config).Check(path, fileset, ff, &pkginfo)
if err != nil {
panic(err)
}
return typespkg, pkginfo
}
func main() {
pkgpath := "/home/pietro/go/src/pkg/syscall"
arch = os.Args[1]
pkg, _ := getPackage(pkgpath)
scope := pkg.Scope()
for _, name := range scope.Names() {
obj := scope.Lookup(name)
if obj == nil {
panic(fmt.Errorf("nil object %q from scope %v", name, scope))
}
if !obj.Exported() { // exported names only
continue
}
if _, ok := obj.(*types.Const); ok {
fmt.Printf("egrep -rh '#define[ ]+%s' ~/winshare/Include/ 2>/dev/null\n", obj.Name())
}
// otherwise skip
}
}
Let's say I have the stupidest ring buffer in the world.
size: constant := 16;
subtype T is integer;
package RingBuffer is
procedure Push(value: T);
function Pop return T;
end;
package body RingBuffer is
buffer: array(0..size) of T;
readptr: integer := 0;
writeptr: integer := 1;
procedure Push(value: T) begin
buffer(writeptr) := value;
writeptr := (writeptr + 1) mod size;
end;
function Pop return T
begin
readptr := (readptr + 1) mod size;
return buffer(readptr);
end;
end;
Because my code sucks, I want to add preconditions and postconditions to make I don't misuse this sure. So I change the implementation of Push as follows:
procedure Push(value: T) with
pre => readptr /= writeptr
is begin
buffer(writeptr) := value;
writeptr := (writeptr + 1) mod size;
end;
However, I get a compile error because I need to put the aspect definitions in the declaration of the procedure, not in the implementation.
The thing is, this is a package. My declaration is public. The values that the precondition is depending on belong to the package body, which isn't visible to the declaration. In order to put the aspect definition in the declaration I'm going to have to refactor my code to expose implementation details into the public part of the package (in this case, readptr and writeptr). And I don't want to do that.
I can think of a few ways round this, such as having my implementation of Push() call a private PushImpl() procedure defined only in the body which actually has the precondition... but that's horrible. What's the right way to do this?
I think this is always going to be a problem when the validation checks are private, and that the solution is to declare a function to do the check:
package RingBuffer is
function Is_Full return Boolean;
procedure Push(value: T) with Pre => not Is_Full;
function Pop return T;
(Is_Full is probably useful anyway; in other cases it might not be so).
If you leave the implementation in the package body, you’ll need to put Is_Full there too, but you could move them to the spec and use an expression function:
package RingBuffer is
function Is_Full return Boolean;
procedure Push(value: T) with Pre => not Is_Full;
function Pop return T;
private
buffer: array(0..size) of T;
readptr: integer := 0;
writeptr: integer := 1;
function Is_Full return Boolean is (Readptr = Writeptr);
end RingBuffer;
The contract aspects are intended to be used in the public view of (sub)types and subprograms.
If you want to keep the check in the private view, then it is simple to write it as the first statement in the subprogram:
begin
if Is_Full then
raise Constraint_Error with "Ring buffer is full.";
end if;
...
Some unsolicited advise:
Make the contracts public, so the users of the package can see how it should be used.
Insert a similar Is_Empty check when popping an item from the buffer.
Make your index type modular: type Indexes is mod 16;
function Java_com_erm_controller_ARMReports_S35(PEnv: PJNIEnv; Obj: JObject; ex_UserRowID, ex_BSID : Integer; ex_RevalDate : JString;
ex_AFS, ex_HTM, ex_HFT : Boolean;
ex_IsMcCaulay_PNL: Boolean;
ex_Maturity, ex_Scale : JIntArray
): Integer; stdcall; export;
var objRpt : TARMReports;
I : Integer;
Len : JInt; //just a renamed delphi integer
aMaturity:array of Integer;
aScale:array of Integer;
begin
DLLErrorLog('CASH -S35');
objRpt := TARMReports.Create; JVM := TJNIEnv.Create(PEnv); ex_RevalDate_J := JVM.JStringToString(ex_RevalDate);
Len:=PEnv^.GetArrayLength(PEnv, ex_Maturity);
SetLength(aMaturity, Len);
Len:=PEnv^.GetArrayLength(PEnv, ex_Scale);
SetLength(aScale, Len);
DLLErrorLog('ex_Maturity Length'+ intToStr(Len));
for I := 0 to Len-1 do
begin
PEnv^.GetIntArrayRegion(PEnv, ex_Maturity, I, Len, #aMaturity[I]);
DLLErrorLog('ex_Maturity '+ IntToStr(aMaturity[I]));
PEnv^.GetIntArrayRegion(PEnv, ex_Scale, I, Len, #aScale[I]);
DLLErrorLog('ex_Scale '+ IntToStr(aScale[I]));
end;
Result := objRpt.S35(ex_UserRowID, ex_BSID, ex_RevalDate_J,
ex_AFS, ex_HTM, ex_HFT ,
ex_IsMcCaulay_PNL,
aMaturity, aScale
);
DLLErrorLog('CASH2 Ends -S35');
JVM.Free; objRpt.Free;
end;
Need to convert ex_Maturity, ex_Scale to objects to Delphi's Array of Integer.
Now while calling from Java it throws java.lang.ArrayIndexOutOfBoundsException
While printing in Log array values are getting . Please suggest us to work for me.
There are a couple of ways, depending on what, exactly your JIntArray is.
Firstly, if its an array of int (as in the primitive java type) then a get the length of the array via JNI, allocate a delphi array of integers and then get JNI to copy the data from the java array
Uses
AndroidAPI.JNI;
Var
Len:JNIInt; //just a renamed delphi integer
aMaturity:array of integer;
begin
Len:=PEnv^.GetArrayLength(PEnv, ex_Maturity);
//allocate the receiving array
SetLength(aMaturity, Len);
//now get the array data - note we are passing the address of the first element
//not the address of the array itself!
PEnv^.GetIntArrayRegion(PEnv, ex_Maturity, 0, Len, #aMaturity[0]);
//do stuff
end;
If you are dealing with an array of Integer (thats the Java class "Integer") then you need to get the array of objects from JNI one element at a time and use TJNIResolver to get the raw value;
Uses
AndroidAPI.JNI, AndroidAPI.JNIBridge;
Var
Len:JNIInt; //just a renamed delphi integer
Count:Integer;
Current:JNIObject;
CurrentValue:integer;
aMaturity:array of integer;
begin
Len:=PEnv^.GetArrayLength(PEnv, ex_Maturity);
//allocate the receiving array
SetLength(aMaturity, Len);
For Count:=0 to Len-1 do
begin
Current:=PEnv^.GetObjectArrayElement(PEnv, ex_Maturity, Count);
if assigned(Current) then
begin
CurrentValue:=TJNIResolver.GetRawValueFromJInteger(Current);
//Yes, you can inline this but the point is, here you do stuff with
//the element
aMaturity[Count]:=CurrentValue;
end;
end;
end;
Obviously the first method is much faster as crossing the JNI barrier is slow and you are only doing it once, whereas with the array of Java Integers you are doing it multiple times for each element.
You should also watch out for errors - I'm not checking for Java exceptions at any point which could crash and burn your app if you don't deal with them.
Edit : The OP has ready my answer and tried to work with it, which is nice. They have gotten a out of bounds exception in their code.
function Java_com_erm_controller_ARMReports_S35(PEnv: PJNIEnv; Obj: JObject; ex_UserRowID, ex_BSID : Integer; ex_RevalDate : JString;
ex_AFS, ex_HTM, ex_HFT : Boolean;
ex_IsMcCaulay_PNL: Boolean;
ex_Maturity, ex_Scale : JIntArray
): Integer; stdcall; export;
var objRpt : TARMReports;
I : Integer;
Len : JInt; //just a renamed delphi integer
aMaturity:array of Integer;
aScale:array of Integer;
begin
DLLErrorLog('CASH -S35');
objRpt := TARMReports.Create; JVM := TJNIEnv.Create(PEnv); ex_RevalDate_J := JVM.JStringToString(ex_RevalDate);
//you only have 1 length defined and possibly different array lengths
//process arrays seperately
Len:=PEnv^.GetArrayLength(PEnv, ex_Maturity);
SetLength(aMaturity, Len);
DLLErrorLog('ex_Maturity Length'+ intToStr(Len));
//only call this once, also watch the parameters you are passing in
PEnv^.GetIntArrayRegion(PEnv, ex_Maturity, 0, Len, #aMaturity[0]);
Len:=PEnv^.GetArrayLength(PEnv, ex_Scale);
SetLength(aScale, Len);
DLLErrorLog('ex_Scale Length'+ intToStr(Len));
PEnv^.GetIntArrayRegion(PEnv, ex_Scale, 0, Len, #aScale[0]);
Result := objRpt.S35(ex_UserRowID, ex_BSID, ex_RevalDate_J,
ex_AFS, ex_HTM, ex_HFT ,
ex_IsMcCaulay_PNL,
aMaturity, aScale
);
DLLErrorLog('CASH2 Ends -S35');
JVM.Free; objRpt.Free;
end;
What you were doing was getting the length twice, setting the delphi arrays correctly but then looping over them both in the same loop not taking into account that they could be different lengths. Your call to getinarrayregion was also passing the complete length in for aScale on the second parameter for both calls - if you really want to get each one in a loop like that then you need to pass the count and a length of 1 to only return 1 element - this is most likely what was causing the exception.
If you want to report the contents then create a procedure to do it, rather than using a loop inside your current procedure, you would have to copy and paste the loop to do it otherwise which is, franky bad coding practice and we don't want that now do we?
Sarcasm on
Not that expecting someone who has tried to help you to correct the your code rather than actually understanding the problem is any better, but ho hum.
Sarcasm off