In Unix, Go can do this:
// func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error)
syscall.Mmap(., ., ., ., syscall.MAP_SHARED|syscall.XXX)
In Windows, you can use this:
https://github.com/golang/go/blob/master/src/syscall/zsyscall_windows.go#L970-L981
// func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error)
syscall.CreateFileMapping(., ., syscall.PAGE_READONLY, ., ., nil)
But I don't see any flag arguments to CreateFileMapping for Windows.
Does anybody know how to pass flags to CreateFileMapping function like syscall.MAP_SHARED|syscall.XXX?
It looks like you can get the integer values for the protection flags from the Windows reference for that syscall. There doesn't seem to be a one-to-one mapping with the Unix-y flags, e.g. rather than having a flag for shared maps, it appears you get a shared map by default when you pass the call a filename.
Related
The following dart code's expected output is the handle to the file explorer window but the output always comes out to be 0 even though the file explorer window does exist!
import 'package:ffi/ffi.dart';
import 'dart:ffi';
void main() {
DynamicLibrary dl = DynamicLibrary.open('user32.dll');
final func = dl.lookupFunction<
IntPtr Function(Pointer<Utf16>?, Pointer<Utf16>?),
int Function(Pointer<Utf16>?, Pointer<Utf16>?)
>('FindWindowA');
print(func(nullptr, 'File Explorer'.toNativeUtf16()));
}
I have ran the function FindWindowA in a c++ program and it has returned the exptected output with the same input values that are NULL and 'File Explorer'.
In dart using null throws the error Invalid argument(s): argument value for ':ffi_param1' is null; hence the use of nullptr
FindWindowA does not take pointers to UTF-16 strings. The A in FindWindowA stands for "ANSI", which is Microsoft's way of indicating that it uses strings with single-byte code units encoded in the system's local encoding. (This is also indicated by its signature, which takes LPCSTR arguments.)
If you want to pass UTF-16 strings (which in Microsoft Windows are considered "wide strings"), then use FindWindowW.
I am writing an F# script that uses Tcl/Tk. Depending on how I call Tcl/Tk from F#, I am experiencing memory corruption. My best guess is that the memory corruption occurs because the F# garbage collector is moving the location of functions around when I allocate memory. Tcl/Tk obviously does not know about this movement and so bad things happen. I am trying to understand why one method produces memory corruption and ones does not.
The simplest code that shows the problem is below:
open System
open System.Runtime.InteropServices
// -----Tcl-----
// Change this literal to point to appropriate Tcl .dll
[<Literal>]
let TclDll = "c:/Tcl32/bin/tcl86.dll"
// Must have the MarshalAs attribute for objs:ObjPtr[] otherwise the array is assumed to be of size 1.
// The SizeParamIndex parameter specifies the int (the second argument) as being the length of the array.
[<UnmanagedFunctionPointer(CallingConvention.Cdecl)>]
type ObjCmdProc = delegate of nativeint * nativeint * int * [<MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2s)>]objs:nativeint[] -> int
[<UnmanagedFunctionPointer(CallingConvention.Cdecl)>]
type CmdDeleteProc = delegate of nativeint -> unit
// 94 EXTERN Tcl_Interp * Tcl_CreateInterp(void);
[<DllImport(TclDll, EntryPoint="Tcl_CreateInterp", CallingConvention=CallingConvention.Cdecl)>]
extern nativeint tclCreateInterp()
// 180 EXTERN int Tcl_Init(Tcl_Interp *interp);
[<DllImport(TclDll, EntryPoint="Tcl_Init", CallingConvention=CallingConvention.Cdecl)>]
extern int tclInit(nativeint interp)
// 96 EXTERN Tcl_Command Tcl_CreateObjCommand(Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc);
[<DllImport(TclDll, EntryPoint="Tcl_CreateObjCommand", CallingConvention=CallingConvention.Cdecl)>]
extern nativeint tclCreateObjCommand(nativeint interp, string cmdName, ObjCmdProc proc, nativeint clientData, CmdDeleteProc deleteProc)
// 291 EXTERN int Tcl_EvalEx(Tcl_Interp *interp, const char *script, int numBytes, int flags);
[<DllImport(TclDll, EntryPoint="Tcl_EvalEx", CallingConvention=CallingConvention.Cdecl)>]
extern int tclEvalEx(nativeint interp, string script, int numBytes, int flags)
// -----Tk-----
// Change this literal to point to appropriate Tk .dll
[<Literal>]
let TkDll = "c:/Tcl32/bin/tk86.dll"
// 0 EXTERN void Tk_MainLoop(void);
[<DllImport(TkDll, EntryPoint="Tk_MainLoop", CallingConvention=CallingConvention.Cdecl)>]
extern void tkMainLoop()
// 118 EXTERN int Tk_Init(Tcl_Interp *interp);
[<DllImport(TkDll, EntryPoint="Tk_Init", CallingConvention=CallingConvention.Cdecl)>]
extern int tkInit(nativeint interp)
// -----Main program-----
// Initialize the Tcl/Tk interpreter
let interp = tclCreateInterp()
tclInit(interp) |> ignore
tkInit(interp) |> ignore
// Direct ObjCmdProc
let testMemDirect = ObjCmdProc (fun clientData interp objCount objs ->
let mem = seq {for i in 0..1000000 -> i} |> Seq.toList
printf "%A" mem
0)
// Indirect ObjCmdProc (via createObjCmd)
let testMemIndirect (objs:nativeint []) (interp:nativeint) =
let mem = seq {for i in 0..1000000 -> i} |> Seq.toList
printf "%A" mem
0
// Creates an ObjCmdProc given a function
let createObjCmdProc fn = ObjCmdProc (fun clientData interp objCount objs ->
fn objs interp)
// Ignore delete messages
let ignoreDelete = CmdDeleteProc ignore
// Create Tcl commands
tclCreateObjCommand(interp, "testMemDirect", testMemDirect, IntPtr.Zero, ignoreDelete) |> ignore
tclCreateObjCommand(interp, "testMemIndirect", (createObjCmdProc testMemIndirect), IntPtr.Zero, ignoreDelete) |> ignore
// Set up GUI
let evalStr = """
wm title . {}
ttk::frame .f
ttk::button .f.testMemDirect -text {Test Direct} -command {testMemDirect}
ttk::button .f.testMemIndirect -text {Test Indirect} -command {testMemIndirect}
ttk::button .f.exit -text {Exit} -command {exit}
grid .f
grid .f.testMemDirect
grid .f.testMemIndirect
grid .f.exit
"""
tclEvalEx(interp, evalStr, evalStr.Length, 0) |> ignore
// Start Tk
tkMainLoop()
0 // return an integer exit code
I can press the "Test Direct" button as many times as I want and there are no issues. I can press the "Test Indirect" button once without issue. But the second time I press it, I get:
Unhandled Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
The difference between the "Test Direct" button and the "Test Indirect" button is that "Test Direct" calls tclCreateObjCommand with an ObjCmdProc delegate while "Test Indirect" calls tclCreateObjCommand with a function that produces an ObjCmdProc delegate.
I am guessing that in the "Test Direct" case, F# is pinning the ObjCmdProc delegate and so there is no memory corruption. However, in the "Test Indirect" case, F# is moving the location of the delegate in response to garbage collection. (Note that this issue only shows itself when there is a large memory allocation - i.e., I am generating a large sequence and converting it into a list).
Assuming that my guess is correct (which it may not be), why is F# behaving like this? And more importantly, is there a way I can tell F# to not move the location of this function in memory? I have tried various things such as GC.KeepAlive and GCHandle.Alloc with no success.
Addendum:
To fix this problem, all I had to do is keep a reference to (createObjCmdProc testMemIndirect). So replace:
tclCreateObjCommand(interp, "testMemIndirect", (createObjCmdProc testMemIndirect), IntPtr.Zero, ignoreDelete) |> ignore
with:
let testMemIndirectRef = createObjCmdProc testMemIndirect
tclCreateObjCommand(interp, "testMemIndirect", testMemIndirectRef, IntPtr.Zero, ignoreDelete) |> ignore
Otherwise, F# thinks that function can be garbage collected. It is possible I might also have to change the ending code from:
// Start Tk
tkMainLoop()
0 // return an integer exit code
to:
// Start Tk
tkMainLoop()
GC.KeepAlive(testMemDirect)
GC.KeepAlive(testMemIndirectRef)
0 // return an integer exit code
to ensure the delegates are kept alive til the end of the program.
Note that at this point I am not concerned with the deletion of Tcl commands even though at some point I might be (as the answer to this question rightfully points out).
At the C level, the clientData parameter (which you've been setting to IntPtr.Zero) is how you'd pass around a pointer to some context that you need to correctly invoke a function that implements a command. Without it, you've just got a pure pointer to a function. The correct thing therefore is to find some way to pass the fn through that mechanism; you need to retain a reference to it until the registered cmdDeleteProc is called, and that callback's primary task is the dropping of that (owning!) reference (it'll be called whenever the command is deleted from the Tcl side of things). This is how Tcl's command implementation API is designed to work; you're strongly advised to work with it.
I think it is working in the case of the “direct” call because the reference from the variables in F# is keeping the function alive. You're fairly lucky it didn't blow up on you in that case as well, since it definitely still isn't safe.
I don't know how to pass a pointer to an F# function instance via a raw pointer. You might need to put it in a plain data structure of some kind and pass a pointer to that around. I also don't know how to tell the F# garbage collector that that data reference can't be collected until you say otherwise (i.e., until the Tcl deletion callback is done). But those are the things that you must do. You probably don't want to expose the details of this directly to most of your F# code; the connector library is something you're going to want to write just once and then have that deal with the details of integrating the .NET and Tcl memory management domains (which is basically classic C, except with a custom memory allocator for more speed).
I want to create a vector of functions
let all_rerankers = vec![ match_full
, match_partial
, match_regex
, match_camel_case
];
However, match_camel_case needs one more parameter than other functions, so I though I could define a closure for match_camel_case
// 3 is the extra parameter needed by match_camel_case
let close_camel_case = |str: &str, keyword: &str| {
match_camel_case(str, keyword, 3)
};
and then specify the type of my vector:
let all_rerankers: Vec<|str: &str, kwd: &str| -> MatchScore>
= vec![ match_full
, match_partial
, match_regex
, close_camel_case
];
However compiling it shows me that Rust treats them differently:
mismatched types: expected `fn(&str, &str) -> MatchScore`,
found `|&str, &str| -> MatchScore`
(expected extern fn, found fn)
close_camel_case
^~~~~~~~~~~~~~~~
(and similar type error in my vec! macro)
It also seem to distinguish between Fn type and closure type. I can make this compile by wrapping every match_* function in a closure, but I'm sure there's a better solution.
Question:
What is the actual mismatch here? the error message seems to suggest Fn vs closure type, but then there's also expected extern fn, found fn in the error message
How can I make the type match? (namely, convert closure into fn type, since it's pure)
my rustc version: rustc 0.12.0-pre-nightly (09cebc25a 2014-09-07 00:31:28 +0000) (can upgrade if needed)
This looks like some unfortunate problem in type inference. If you do this:
let mut all_rerankers: Vec<|str: &str, kwd: &str| -> MatchScore> = Vec::new();
all_rerankers.push(match_full);
all_rerankers.push(match_partial);
all_rerankers.push(match_regex);
all_rerankers.push(close_camel_case);
Then everything is fine. The duplication is extensive, but you can easily write a macro whose invocation could look like this:
push_to!(all_rerankers;
match_full,
match_partial,
match_regex,
close_camel_case
)
This probably deserves creating an issue in Rust bug tracker, but old closures will be deprecated soon, so I'm not sure if this is worth fixing.
when i recvfrom(), the received message is correct, but the source address is totally a mess,
why is that happening?
char traid_messageR[MAXDATASIZE];
socklen_t addlen;
struct sockaddr_in source_addr;
if((numbytes=recvfrom(udp_sockfd, traid_messageR, 256, 0, (struct sockaddr*)&source_addr, &addlen)) == -1)
{
perror("recvfrom");
exit(1);
}
the result is like this:
(gdb) print source_addr
$1 = {sin_family = 61428, sin_port = 42, sin_addr = {s_addr = 49809},
sin_zero = "\234\352\377\277\310\352\377\277"}
the 49809 looks like a port number, but it is the port number of this receiver...does any one have idea why is this?thanks a lot
oh, another thing, i used this in a select() loop, IF_ISSET(und_socked,%fds),then exceute the above code, does this affect?
you didn't assign value to addlen
addlen = sizeof(source_addr)
UPDATE: refer to http://pubs.opengroup.org/onlinepubs/7908799/xns/recvfrom.html
The manual says
address_len Specifies the length of the sockaddr structure pointed
to
by the address argument. .....
If the address argument is not a null pointer and the protocol provides the source address of messages, the source address of the
received message is stored in the sockaddr structure pointed to by the
address argument, and the length of this address is stored in the
object pointed to by the address_len argument.
I found it explained better here:
In this case, addrlen is a value-
result argument. Before the call, it should be initialized to the
size of the buffer associated with src_addr. Upon return, addrlen is
updated to contain the actual size of the source address.
http://man7.org/linux/man-pages/man2/recv.2.html
I was trying to figure out how file operations in drivers work. I know there are several file operations but the functions for these operations are called with several arguments while the operations themselves are defined without any.
So if I have this -
static const struct file_operations proc_myled_operations = {
.open = proc_myled_open,
.read = seq_read,
.write = proc_myled_write,
.llseek = seq_lseek,
.release = single_release
};
Now I know that kernel level drivers can only be accessed as files from the user application. This is an embedded system so I have some LEDs that I can turn on by writing to their memory mapped registers.
So the .write or "proc_myled_write" call will execute when I turn an led on which I can do by opening this file using fopen and then writing to it by using fputs. But if .write is mapped as "proc_myled_write and this function has arguments like so -
static ssize_t proc_myled_write(struct file *file, const char __user * buf,
size_t count, loff_t * ppos)
What happens to the arguments? There is no function call for the above function with those arguments. I've seen this in several drivers. I just used this one because it was a simple example. How are the file operations mapped to these functions? How does the, for example, "write" in user space trace to the write in the driver?
Thank you.
I'm not exactly sure what you mean when you say "There is no function call for the above function with those arguments."
The prototype for these functions is defined in the declaration for struct file_operations itself.
Here is the first few lines from the struct declaration:
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
...
While the arguments are not named in the declaration, you can clearly see that the write() function is declared with 4 parameters matching the types that you mention in your question.
When you assign the function to its appropriate field (proc_myled_operations.write = proc_myled_write) you are simply passing a pointer to the write function declared and defined in your module. Pointers to functions themselves do not need parameters.
Ok, so you're question really is: "How does the user space system call eventually call the write function in your module?" Good question! I recommend editing your question to make that clearer for future readers.
Well, let's see if I can follow the paper trail. I discovered this document to give me the starting location to look in the code for the write() system call. It's very very old, but hey, not everything changes in the kernel! We start our journey at the write() system call declaration in fs/read_write.c:
SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
size_t, count)
It uses the file descriptor fd to get the struct file created when you registered your character driver. Then it gets the current position in the file and calls vfs_write().
ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
And it is in this function see the following line:
ret = file->f_op->write(file, buf, count, pos);
There it is!
To allay any doubts as to the type of file->f_op, we take a look at the definition of struct file and see the following definition for the f_op field:
const struct file_operations *f_op;
So it must be the struct file_operations you passed in when you registered your driver. Phew!
Hopefully all of these links will show you how to follow the trail for other system calls if you are curious.
#Maverick, write prototype or signature in kernel is ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *). From user space application you will be issuing open, write system call to turn on/off the LED. Write system call signature in user space is int write(int fd, const char *buf, size_t count). So when you call write from user space, fd (file descriptor) passed reaches the virtual file system(vfs), maintains linked list of the open file descriptor table(OFDT), thus according to the fd, OFDT has an pointer filp (file pointer) which point to the file opened for ex: device node "/dev/xxx" or any other file for that matter. The rest buf and count are same arguments passed from the user space to the kernel space. Last loff_t *fpos comes into picture if you want to seek the file for ex: using lseek or fseek on the file opened, if seek then the file pointer(loff_t fpos) position gets changed accordingly. Hope I cleared your doubt :-)