我正在开发一个需要与Video4Linux抽象交互的应用程序。该应用程序使用mono框架以C#开发。
我面临的问题是我无法P /调用ioctl
系统调用。或者,更准确地说,我可以P /调用它,但是它崩溃严重。
extern声明如下:
[DllImport("libc", EntryPoint = "ioctl", SetLastError = true)]
private extern static int KernelIoCtrl(int fd, int request, IntPtr data);
到目前为止,一切都很好。
使用的实际例程KernelIoCtrl
如下:
protected virtual int Control(IoSpecification request, object data)
{
GCHandle dataHandle;
IntPtr dataPointer = IntPtr.Zero;
try {
// Pin I/O control data
if (data != null) {
dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
dataPointer = dataHandle.AddrOfPinnedObject();
}
// Perform I/O control
int result = KernelIoCtrl(mFileDescriptor, request.RequestCode, dataPointer);
int errno = Marshal.GetLastWin32Error();
// Throw exception on errors
if (errno != (int)ErrNumber.NoError)
throw new System.ComponentModel.Win32Exception(errno);
return (result);
} finally {
if (dataPointer != IntPtr.Zero)
dataHandle.Free();
}
}
以上所有代码似乎都不错。该类IoSpecification
用于按照标头规范计算I /
O请求代码(基本上,它遵循处_IOC
声明的宏)/usr/include/linux/asm/ioctl.h
。
该data
参数是一个结构,声明如下:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Capability
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string Driver;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string Device;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string BusInfo;
public UInt32 Version;
public CapabilityFlags Capabilities;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
public UInt32[] Reserved;
}
应该模仿以下结构(在处声明/usr/include/linux/videodev2.h
):
struct v4l2_capability {
__u8 driver[16]; /* i.e. "bttv" */
__u8 card[32]; /* i.e. "Hauppauge WinTV" */
__u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */
__u32 version; /* should use KERNEL_VERSION() */
__u32 capabilities; /* Device capabilities */
__u32 reserved[4];
};
在发生崩溃之前,IOCTL请求代码计算存在问题,并且KernelIoCtrl
按预期方式工作(返回errno
等于 EINVAL
)。当我更正了该错误(并确实具有正确的IOCTRL请求代码)后,该调用已开始导致崩溃。
总而言之,似乎在结构编组中存在问题,但是我看不到它出了什么问题。
我担心问题出在变量参数列表中,因为 ioctl 例程被声明为follow(从man中获取):
int ioctl(int d, int request, ...);
但是我看到很多代码将上述例程声明为int ioctl(int d, int request, void*);
,并且可以确保特定的IOCTRL请求仅接受一个参数。
用法示例:
Capability capability;
if (UnsafeNativeMethods.Ioctl(handle, request, ref capability) == -1)
{
throw new UnixIOException();
}
能力:
[StructLayout(LayoutKind.Sequential, Size = 104)]
internal struct Capability
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string Driver;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string Device;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string BusInfo;
public uint Version;
public CapabilityFlags Capabilities;
}
UnsafeNativeMethods:
internal static class UnsafeNativeMethods
{
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport("libc", EntryPoint = "close", SetLastError = true)]
internal static extern int Close(IntPtr handle);
[DllImport("libc", EntryPoint = "ioctl", SetLastError = true)]
internal static extern int Ioctl(SafeUnixHandle handle, uint request, ref Capability capability);
[DllImport("libc", EntryPoint = "open", SetLastError = true)]
internal static extern SafeUnixHandle Open(string path, uint flag, int mode);
internal static string Strerror(int error)
{
try
{
var buffer = new StringBuilder(256);
var result = Strerror(error, buffer, (ulong)buffer.Capacity);
return (result != -1) ? buffer.ToString() : null;
}
catch (EntryPointNotFoundException)
{
return null;
}
}
[DllImport("MonoPosixHelper", EntryPoint = "Mono_Posix_Syscall_strerror_r", SetLastError = true)]
private static extern int Strerror(int error, [Out] StringBuilder buffer, ulong length);
}
SafeUnixHandle:
[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
internal sealed class SafeUnixHandle : SafeHandle
{
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
private SafeUnixHandle()
: base(new IntPtr(-1), true)
{
}
public override bool IsInvalid
{
get { return this.handle == new IntPtr(-1); }
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
return UnsafeNativeMethods.Close(this.handle) != -1;
}
}
UnixIOException:
[Serializable]
public class UnixIOException : ExternalException
{
private readonly int nativeErrorCode;
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
public UnixIOException()
: this(Marshal.GetLastWin32Error())
{
}
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
public UnixIOException(int error)
: this(error, GetErrorMessage(error))
{
}
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
public UnixIOException(string message)
: this(Marshal.GetLastWin32Error(), message)
{
}
public UnixIOException(int error, string message)
: base(message)
{
this.nativeErrorCode = error;
}
public UnixIOException(string message, Exception innerException)
: base(message, innerException)
{
}
protected UnixIOException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
this.nativeErrorCode = info.GetInt32("NativeErrorCode");
}
public int NativeErrorCode
{
get { return this.nativeErrorCode; }
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info == null)
{
throw new ArgumentNullException("info");
}
info.AddValue("NativeErrorCode", this.nativeErrorCode);
base.GetObjectData(info, context);
}
private static string GetErrorMessage(int error)
{
var errorDescription = UnsafeNativeMethods.Strerror(error);
return errorDescription ?? string.Format("Unknown error (0x{0:x})", error);
}
}
本章描述 Linux 内核中的系统调用概念。 系统调用概念简介 - 介绍 Linux 内核中的系统调用概念 Linux 内核如何处理系统调用 - 介绍 Linux 内核如何处理来自于用户空间应用的系统调用。 vsyscall and vDSO - 介绍 vsyscall 和 vDSO 概念。 Linux 内核如何运行程序 - 介绍一个程序的启动过程。 open 系统调用的实现 - 介绍 open
系统调用sendfile Sendfile是Linux实现的系统调用,可以通过避免文件在内核态和用户态的拷贝来优化文件传输的效率。 其中大名鼎鼎的分布式消息队列服务Kafka就使用sendfile来优化效率,具体用法可参见其官方文档。 优化策略 在普通进程中,要从磁盘拷贝数据到网络,其实是需要通过系统调用,进程也会反复在用户态和内核态切换,频繁的数据传输在此有效率问题。因此我们必须意识到Linux
系统调用 我们要想启动一个进程,需要操作系统的调用(system call)。实际上操作系统和普通进程是运行在不同空间上的,操作系统进程运行在内核态(todo: kernel space),开发者运行的进程运行在用户态(todo: user space),这样有效规避了用户程序破坏系统的可能。 如果用户态进程想执行内核态的操作,只能通过系统调用了。Linux提供了超多系统调用函数,我们关注与进程相
11.3.1 默认的调用规范 通常, FreeBSD 的内核使用 C 语言的调用规范。 此外, 虽然我们使用 int 80h 来访问内核, 但是我们常常通过调用一个函数来执行 int 80h, 而不是直接访问。 这个规范是非常方便的, 比 Microsoft® 的 MS-DOS® 上使用的规范更加优越。 为什么呢? 因为 UNIX® 的规范允许任何语言所写的程序访问内核。 汇编语言也可以这样做,
当想知道一个进程在做什么事情的时候,可以通过strace命令跟踪一个进程的所有系统调用。 1、运行 php start.php status 能看到workerman相关进程的信息 如下: Hello admin ---------------------------------------GLOBAL STATUS-----------------------------------------
我刚刚开始研究系统调用。我想知道当进行系统调用时是什么导致了开销。 例如,如果我们考虑getpid(),当系统调用getpid()时,我的猜测是,如果控件当前位于子进程中,则必须进行上下文切换才能进入父进程以获取pid。这会导致间接费用吗? 此外,当调用getpid()时,会有一些元数据跨用户空间边界传输,并进入和退出内核。那么,用户空间和内核之间的不断切换也会导致一些开销吗?