我有一个运行在embedded式设备上的软件(x86,最近的linux)。 为了简化开发,使用自动化testing等,我想在我的主机系统上运行它。 代码编译得很好,对构build系统进行了一些调整。 下一步将是创build“虚拟设备”。
应用程序不使用任何types的库,而是通过读,写和ioctl调用直接与多个设备进行通信。 这些设备使用自定义协议来表示定制硬件。 要创build一个虚拟的环境,我需要回应这个电话。 一种可能的方法是:
/dev/deviceA , /dev/deviceB , /dev/deviceC ,…) /dev/deviceSimulation ) /dev/deviceSimulation /dev/deviceSimulation进行交互,并跟踪模拟的状态。 有没有更简单的方法来做到这一点,而不是通过Linux内核的往返?
回到这个项目并回答我自己的问题:是的,必须完成内核的往返。 但是有一个图书馆在做CUDA(感谢,CL)。
文档感觉有点缺乏(或者我正在看错误的地方),提供的cuda示例中充满了其他一些处理参数或缓冲区处理的东西。 所以在这里另一个例子(甚至更多的减少,没有什么有用的发生在这里…):
设备“驱动程序”(cusetest.c):
#define FUSE_USE_VERSION 30 #define _FILE_OFFSET_BITS 64 #include <fuse/cuse_lowlevel.h> #include <fuse/fuse_opt.h> #include <stdio.h> #define LOG(...) do { fprintf(stderr, __VA_ARGS__); puts(""); } while (0) static void cusetest_open(fuse_req_t req, struct fuse_file_info *fi) { LOG("open"); fuse_reply_open(req, fi); } static void cusetest_read(fuse_req_t req, size_t size, off_t off, struct fuse_file_info *fi) { LOG("read"); fuse_reply_buf(req, "Hello", size > 5 ? 5 : size); } static void cusetest_write(fuse_req_t req, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) { LOG("write (%u bytes)", size); fuse_reply_write(req, size); } static void cusetest_ioctl(fuse_req_t req, int cmd, void *arg, struct fuse_file_info *fi, unsigned flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz) { LOG("ioctl %d: insize: %u outsize: %u", cmd, in_bufsz, out_bufsz); switch (cmd) { case 23: if (in_bufsz == 0) { struct iovec iov = { arg, sizeof(int) }; fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0); } else { LOG(" got value: %d", *((int*)in_buf)); fuse_reply_ioctl(req, 0, NULL, 0); } break; case 42: if (out_bufsz == 0) { struct iovec iov = { arg, sizeof(int) }; fuse_reply_ioctl_retry(req, NULL, 0, &iov, 1); } else { LOG(" write back value"); int v = 42; fuse_reply_ioctl(req, 0, &v, sizeof(int)); } break; } } static const struct cuse_lowlevel_ops cusetest_clop = { .open = cusetest_open, .read = cusetest_read, .write = cusetest_write, .ioctl = cusetest_ioctl, }; int main(int argc, char** argv) { // -f: run in foreground, -d: debug ouput // Compile official example and use -h const char* cusearg[] = {"test", "-f", "-d"}; const char* devarg[] = {"DEVNAME=cusetest" }; struct cuse_info ci; memset(&ci, 0x00, sizeof(ci)); ci.flags = CUSE_UNRESTRICTED_IOCTL; ci.dev_info_argc=1; ci.dev_info_argv = devarg; return cuse_lowlevel_main(3, (char**) &cusearg, &ci, &cusetest_clop, NULL); }
编译并运行: gcc -Wall -g -lfuse cusetest.c -o cusetest && sudo ./cusetest
测试程序(testcusetest.c):
#include <fcntl.h> #include <unistd.h> #include <string.h> #include <stdio.h> #include <sys/ioctl.h> int main() { int fd = open("/dev/cusetest", O_RDWR); const char* msg = "Fooooo"; write(fd, msg, strlen(msg)); int v = 63; ioctl(fd, 23, &v); fprintf(stderr, "value is now: %d\n", v); ioctl(fd, 42, &v); fprintf(stderr, "value is now: %d\n", v); close(fd); return 0; }
编译并运行: gcc -Wall testcusetest.c -o testcusetest && ./testcusetest
它还有更多的事情要做,但应该足以得到startet。 一个陷阱是CUSE_UNRESTRICTED_IOCTL 。 如果输入或输出缓冲区的长度为零,则需要使用fuse_reply_ioctl_retry()进行回复。 回调将被填充缓冲区再次调用。