How to pass array(or vec) between Go and Rust? - rust

I want to build a local service mainly based on Golang, and I'm using Rust to reshape part of my code to make it run faster and cost less memory. Everything went well until I tried to pass an array between them.
I've defined the same data structure in both Rust and Go, and they work well separately, but I don't know how to pass an array.
Here are my structure definitions:
// go part
type ContractItems []ContractItem // Here `ContractItem` is another plain struct with simple k-v structure.
// rust part
type ContractItems Vec<ContractItem>
// c header file
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct Vec_ContractItemPrice Vec_ContractItemPrice;
typedef struct Vec_ContractItemPrice ContractItemPrices;
struct ContractItemsPriceHandler contract_items_price_handler_from(ContractItemPrices c, int64_t contract_id);
I haven't use Clang for actually a long time, so the C header file was generated automatically by cbindgen.
And I received this panic report:
# command-line-arguments
cgo-gcc-prolog: In function '_cgo_fbbb6cfe6006_Cfunc_contract_items_price_handler_from':
cgo-gcc-prolog:46:22: error: field 'p0' has incomplete type
cgo-gcc-prolog:53:45: error: type of formal parameter 1 is incomplete
I expect to pass an array or array-like which can be transferred into both alloc::vec or just array in Rust and slice or array in Go. Anyway, I'm not quite good at Clang. So the possible solutions in Rust or Go part are more appreciated since I'm not sure about my ability to debug additional C code.

Related

What is the significance of THIS_MODULE in Linux kernel module drivers?

In Linux device driver development, the file_operations structure uses struct module *owner.
What is the use of this structure when we always initialize it with THIS_MODULE?
When can this field be set to NULL?
This field tells who is owner of struct file_operations. This prevents module to get unloaded when it is in operation. When initialized with THIS_MODULE current module holds the ownership on it.
Minimal runnable example
Whenever you create a kernel module, the kernel's build machinery generates a struct module object for you, and makes THIS_MODULE point to it.
This struct contains many fields, some of which can be set with module macros such as MODULE_VERSION.
This example shows how to access that information: module_info.c:
#include <linux/module.h>
#include <linux/kernel.h>
static int myinit(void)
{
/* Set by default based on the module file name. */
pr_info("name = %s\n", THIS_MODULE->name);
pr_info("version = %s\n", THIS_MODULE->version);
return 0;
}
static void myexit(void) {}
module_init(myinit)
module_exit(myexit)
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
Dmesg outputs:
name = module_info
version = 1.0
Some MODULE_INFO fields can also be "accessed" in the following ways:
cat /sys/module/module_info/version
modinfo /module_info.ko | grep -E '^version:'
Since the address of that struct module object must be unique across all modules, it serves as a good argument for fops.owner as mentioned at: https://stackoverflow.com/a/19468893/895245. Here is a minimal example of that usage.
Tested in Linux kernel 4.16 with this QEMU + Buildroot setup.
[1] struct module *owner is commonly used at some structures and is not an operation at all; it is a pointer to the module that "owns"the structure. This field is used to prevent the module from being unloaded while its operations are in use. Almost all the time, it is simply initialized to THIS_MODULE, a macro defined in
< linux/module.h> .
.
[2] I would not recommend you to set it to null, because it may lead to driver malfunction and other problems. Instead, use the good practices of linux kernel development.
In some architectures the ".owner" was removed, so, make sure your distro and architecture still using it.
I hope it helps your understanding.
References: LDD3, kernel newbies.
file_operation is one of the main structures that used to connect the device numbers and the file operations of a driver.
There are lots of function pointer in the structure. The first pointer is struct module *owner which is not a function pointer at all but points to a structure module defined in the <linux/module.h>.
On initializing to THIS_MODULE, it holds the ownership of the module.
One of the main reasons to initialize struct module *owner to THIS_MODULE to prevent the module from getting unloaded while in use.

C Program to Store ttyUSB* devices in an array

AM having a C program which uses system to list /dev/ttyUSB* devices how can I store them in an array and process.
#include <stdio.h>
#include <stdlib.h>
int main()
{
system("ls /dev/ttyUSB*");
printf("Done");
exit(0);
}
Using system for these things is a bad idea.
First of all, you have to Parse the output of ls, which you should avoid.
Apart from that, this will be quite inefficient. starting programs is rather slow, but you are running a program (written in C), that starts another program (written in C) which calculates something and renders this something into a human-readable form, and then you have to parse the human-readable form to find out what the original something was...
A better way is to do the shortcut can "calculate the something" directly:
check out glob

Using <linux/types.h> in user programs, or <stdint.h> in driver module code...does it matter?

I'm developing a device driver module and associated user libraries to handle the ioctl() calls. The library takes the pertinent info and puts it into a struct, which gets passed into the driver module and unpacked there and then dealt with (I'm omitting a lot of steps, but that's the overall idea).
Some of the data being passed through the struct via the ioctl() is uint32_t type. I've discovered that that type is defined in <stdint.h> AND <linux/types.h>. So far I've been using <linux/types.h> to define that value, including down in the user libraries. But I understand it is bad form to use <linux/*.h> libraries in user space, so if I remove those and use <stdint.h> instead, then when my driver module includes the struct definition, it will have to be including <stdint.h> also.
It seems to me that the point of <linux/types.h> is to define types in kernel files, so I'm not sure if that means using <stdint.h> is bad idea there. I also found that when trying to compile my driver module with <stdint.h>, I get compilation errors about redefinitions that won't go away, even if I replace all instances of <linux/types.h> with <stdint.h> (and put it on the top of the include order).
Is it a bad idea to use linux/*.h includes in user-space code?
Is it a bad idea to use <stdint.h> in kernel-space code?
If the answers to both of those is yes, then how do I handle the situation where a structure containing uint32_t is shared by both the user library and the driver module?
Is it a bad idea to use linux/*.h includes in user-space code?
Yes, usually. The typical situation is that you should be using the C-library headers (in this case, stdint.h and friends), and interface with the C library though those user-space types, and let the library handle talking with the kernel through kernel types.
You're not in a typical situation though. In your case, you're writing the driver library. So you should be presenting an interface to userspace using stdint.h, but using the linux/*.h headers when you interface to your kernel driver.
So the answer is no, in your case.
Is it a bad idea to use stdint.h in kernel-space code?
Most definitely yes.
See also: http://lwn.net/Articles/113349/
Fixed length integers in the Linux kernel
The Linux kernel already has fixed length integers which might interest you. In v4.9 under include/asm-generic/int-ll64.h:
typedef signed char s8;
typedef unsigned char u8;
typedef signed short s16;
typedef unsigned short u16;
typedef signed int s32;
typedef unsigned int u32;
typedef signed long long s64;
typedef unsigned long long u64;
LDD3 has a chapter about data sizes as well: https://static.lwn.net/images/pdf/LDD3/ch11.pdf
LDD3 mentions there that the best printk strategy is to cast to just cast to the largest integer possible with correct signedness: %lld or %llu. %ju appears unavailable under the printk formatting centerpiece lib/linux/vsprintf.c.

Can I use Linux kernel linked list outside kernel code?

I want to play with kernel linked list before I use it in some part of the kernel code. But if I just include list.h, it doesn't work due to dependencies.
How can I write code using list in a single.c file e.g. test.c so that I can test my code just by compiling test.c? Looking forward to hearing from you soon.
Also, how can I use nested linked list?
You can get a userspace port from http://www.mcs.anl.gov/~kazutomo/list/list.h.
It says:
Here is a recipe to cook list.h for user space program
copy list.h from linux/include/list.h
remove
#ifdef KERNE and its #endif
all #include line
prefetch() and rcu related functions
add macro offsetof() and container_of
It is not meant to use the list in Userspace since its made for inside Kernel use and has several dependencies of kernel types and so on. You can see this by compiling your code with correct include paths:
gcc -I path-to-kernel-src/include/ test.c
When test.c contains this code:
#include <stdio.h>
#include <stdlib.h>
#include <linux/list.h>
int main(int argc, char **argv) { }
It fails to compile since there are includes in list.h which conflicts the userspace include (stdlib.h).
Nevertheless, the dependencies of such a data structures like list are pretty small. You need to sort them out in order to break the list.h dependencies from other kernel. In a short test, I removed the includes to and from list.h and added the data types struct list_head/hlist_head and hlist_node.

Question about file seeking position

My previous Question is about raw data reading and writing, but a new problem arised, it seems there is no ending....
The question is: the parameters of the functions like lseek() or fseek() are all 4 bytes. If i want to move a span over 4G, that is imposible. I know in Win32, there is a function SetPointer(...,Hign, Low,....), this pointers can generate 64 byte pointers, which is what i want.
But if i want to create an app in Linux or Unix (create a file or directly write
the raw drive sectors), How can I move to a pointer over 4G?
Thanx, Waiting for your replies...
The offset parameter of lseek is of type off_t. In 32-bit compilation environments, this type defaults to a 32-bit signed integer - however, if you compile with this macro defined before all system includes:
#define _FILE_OFFSET_BITS 64
...then off_t will be a 64-bit signed type.
For fseek, the fseeko function is identical except that it uses the off_t type for the offset, which allows the above solution to work with it too.
a 4 byte unsigned integer can represent a value up to 4294967295, which means if you want to move more than 4G, you need to use lseek64(). In addition, you can use fgetpos() and fsetpos() to change the position in the file.
On Windows, use _lseeki64(), on Linux, lseek64().
I recommend to use lseek64() on both systems by doing something like this:
#ifdef _WIN32
#include <io.h>
#define lseek64 _lseeki64
#else
#include <unistd.h>
#endif
That's all you need.

Resources