@k13engineering/linux-dmabuf-allocator 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,3 @@
1
1
  import { createDefaultDmabufHeapManager } from "./dmabuf-heap/index.js";
2
- export { createDefaultDmabufHeapManager };
2
+ import { createDefaultUdmabufAllocator } from "./udmabuf/index.js";
3
+ export { createDefaultDmabufHeapManager, createDefaultUdmabufAllocator };
package/dist/lib/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { createDefaultDmabufHeapManager } from "./dmabuf-heap/index.js";
2
+ import { createDefaultUdmabufAllocator } from "./udmabuf/index.js";
2
3
 
3
4
  export {
4
- createDefaultDmabufHeapManager
5
+ createDefaultDmabufHeapManager,
6
+ createDefaultUdmabufAllocator
5
7
  };
@@ -16,8 +16,12 @@ const createDefaultDmabufHeapAllocatorLinuxInterface = ()/*: TDmabufHeapKernelIn
16
16
  };
17
17
 
18
18
  const ioctl/*: C["ioctl"]*/ = ({ fd, request, arg }) => {
19
- const { errno } = nativeIoctl({ fd, request, arg });
20
- return { errno };
19
+ const { errno, ret } = nativeIoctl({ fd, request, arg });
20
+ if (errno !== undefined) {
21
+ return { errno, ret: undefined };
22
+ }
23
+
24
+ return { errno, ret };
21
25
  };
22
26
 
23
27
  const dup = ({ fd }/*: { fd: number }*/)/*: number*/ => {
@@ -55,6 +59,55 @@ const createDefaultDmabufHeapAllocatorLinuxInterface = ()/*: TDmabufHeapKernelIn
55
59
  }
56
60
  };
57
61
 
62
+ const fcntl/*: C["fcntl"]*/ = ({ fd, cmd, arg }/*: { fd: number; cmd: number; arg: number }*/) => {
63
+ const { errno } = syscall({
64
+ syscallNumber: syscallNumbers.fcntl,
65
+ args: [BigInt(fd), BigInt(cmd), BigInt(arg)]
66
+ });
67
+
68
+ if (errno !== undefined) {
69
+ return { errno };
70
+ }
71
+
72
+ return { errno: undefined };
73
+ };
74
+
75
+ const textEncoder = new TextEncoder();
76
+
77
+ const memfd_create/*: C["memfd_create"]*/ = ({ name, flags }/*: { name: string; flags: number }*/) => {
78
+
79
+ const nameAsBuffer = textEncoder.encode(`${name} \0`);
80
+
81
+ const { errno, ret } = syscall({
82
+ syscallNumber: syscallNumbers.memfd_create,
83
+ args: [
84
+ nameAsBuffer,
85
+ BigInt(flags)
86
+ ]
87
+ });
88
+
89
+ if (errno !== undefined) {
90
+ return {
91
+ errno,
92
+ memfd: undefined
93
+ };
94
+ }
95
+
96
+ return { errno: undefined, memfd: Number(ret) };
97
+ };
98
+
99
+ const ftruncate/*: C["ftruncate"]*/ = ({ fd, length }/*: { fd: number; length: number }*/) => {
100
+ try {
101
+ nodeFs.ftruncateSync(fd, length);
102
+ } catch (e) {
103
+ return {
104
+ error: e /*as Error*/,
105
+ };
106
+ }
107
+
108
+ return { error: undefined };
109
+ };
110
+
58
111
  const close/*: C["close"]*/ = ({ fd }) => {
59
112
  nodeFs.closeSync(fd);
60
113
  };
@@ -66,6 +119,9 @@ const createDefaultDmabufHeapAllocatorLinuxInterface = ()/*: TDmabufHeapKernelIn
66
119
  dup,
67
120
  readdir,
68
121
  open,
122
+ fcntl,
123
+ memfd_create,
124
+ ftruncate,
69
125
  close
70
126
  };
71
127
  };
@@ -6,7 +6,11 @@ type TDmabufHeapKernelInterface = {
6
6
  request: bigint;
7
7
  arg: Uint8Array;
8
8
  }) => {
9
- errno: undefined | number;
9
+ errno: undefined;
10
+ ret: bigint;
11
+ } | {
12
+ errno: number;
13
+ ret: undefined;
10
14
  };
11
15
  dup: (args: {
12
16
  fd: number;
@@ -33,7 +37,35 @@ type TDmabufHeapKernelInterface = {
33
37
  errno: number;
34
38
  fd: undefined;
35
39
  };
40
+ fcntl: (args: {
41
+ fd: number;
42
+ cmd: number;
43
+ arg: number;
44
+ }) => {
45
+ errno: undefined;
46
+ } | {
47
+ errno: number;
48
+ };
49
+ memfd_create: (args: {
50
+ name: string;
51
+ flags: number;
52
+ }) => {
53
+ errno: undefined;
54
+ memfd: number;
55
+ } | {
56
+ errno: number;
57
+ memfd: undefined;
58
+ };
59
+ ftruncate: (args: {
60
+ fd: number;
61
+ length: number;
62
+ }) => {
63
+ error: undefined;
64
+ } | {
65
+ error: Error;
66
+ };
36
67
  };
37
68
  type TDmabufHeapAllocatorKernelInterface = Pick<TDmabufHeapKernelInterface, "endianness" | "determinePageSize" | "ioctl" | "dup" | "close">;
38
69
  type TDmabufHeapIoctlKernelInterface = Pick<TDmabufHeapKernelInterface, "endianness" | "ioctl">;
39
- export type { TDmabufHeapKernelInterface, TDmabufHeapAllocatorKernelInterface, TDmabufHeapIoctlKernelInterface };
70
+ type TDmabufUdmabufAllocatorKernelInterface = Pick<TDmabufHeapKernelInterface, "endianness" | "determinePageSize" | "fcntl" | "memfd_create" | "ftruncate" | "ioctl" | "close">;
71
+ export type { TDmabufHeapKernelInterface, TDmabufHeapAllocatorKernelInterface, TDmabufHeapIoctlKernelInterface, TDmabufUdmabufAllocatorKernelInterface };
@@ -2,13 +2,18 @@
2
2
  /*type TDmabufHeapKernelInterface = {
3
3
  endianness: "LE" | "BE";
4
4
  determinePageSize: () => number;
5
- ioctl: (args: { fd: number; request: bigint, arg: Uint8Array }) => { errno: undefined | number };
5
+ ioctl: (args: { fd: number; request: bigint, arg: Uint8Array }) => { errno: undefined, ret: bigint } | { errno: number, ret: undefined };
6
6
  dup: (args: { fd: number }) => number;
7
7
  close: (args: { fd: number }) => void;
8
8
 
9
9
  // dmabuf heap listing
10
10
  readdir: ({ path }: { path: string }) => { errno: undefined, entries: string[] } | { errno: number, entries: undefined };
11
11
  open: (args: { path: string, flags: number }) => { errno: undefined, fd: number } | { errno: number, fd: undefined };
12
+
13
+ // udmabuf allocator
14
+ fcntl: (args: { fd: number; cmd: number; arg: number }) => { errno: undefined } | { errno: number };
15
+ memfd_create: (args: { name: string; flags: number }) => { errno: undefined, memfd: number } | { errno: number, memfd: undefined };
16
+ ftruncate: (args: { fd: number; length: number }) => { error: undefined } | { error: Error };
12
17
  };*/
13
18
 
14
19
  /*type TDmabufHeapAllocatorKernelInterface = Pick<TDmabufHeapKernelInterface,
@@ -24,9 +29,20 @@
24
29
  "ioctl"
25
30
  >;*/
26
31
 
32
+ /*type TDmabufUdmabufAllocatorKernelInterface = Pick<TDmabufHeapKernelInterface,
33
+ "endianness" |
34
+ "determinePageSize" |
35
+ "fcntl" |
36
+ "memfd_create" |
37
+ "ftruncate" |
38
+ "ioctl" |
39
+ "close"
40
+ >;*/
41
+
27
42
  /*export type {
28
43
  TDmabufHeapKernelInterface,
29
44
  TDmabufHeapAllocatorKernelInterface,
30
- TDmabufHeapIoctlKernelInterface
45
+ TDmabufHeapIoctlKernelInterface,
46
+ TDmabufUdmabufAllocatorKernelInterface
31
47
  };*/
32
48
  /* c8 ignore stop */
@@ -0,0 +1,3 @@
1
+ import { type TDmabufAllocator } from "../dmabuf-allocator-interface.js";
2
+ declare const createDefaultUdmabufAllocator: () => TDmabufAllocator;
3
+ export { createDefaultUdmabufAllocator, };
@@ -0,0 +1,26 @@
1
+ import { /*type TDmabufAllocator */} from "../dmabuf-allocator-interface.js";
2
+ import { createDefaultDmabufHeapAllocatorLinuxInterface } from "../kernel-interface-impl-linux.js";
3
+ import { createUdmabufAllocatorFactory } from "./udmabuf-allocator.js";
4
+
5
+ const O_RDWR = 0x02;
6
+ const O_CLOEXEC = 0x80000;
7
+
8
+ const createDefaultUdmabufAllocator = ()/*: TDmabufAllocator*/ => {
9
+ const kernelInterface = createDefaultDmabufHeapAllocatorLinuxInterface();
10
+
11
+ const { errno, fd } = kernelInterface.open({
12
+ path: "/dev/udmabuf",
13
+ flags: O_RDWR | O_CLOEXEC
14
+ });
15
+
16
+ if (errno !== undefined) {
17
+ throw Error(`failed to open /dev/udmabuf, errno ${errno}. Is the udmabuf kernel module loaded?`);
18
+ }
19
+
20
+ const udmabufAllocatorFactory = createUdmabufAllocatorFactory({ kernelInterface });
21
+ return udmabufAllocatorFactory.createUdmabufAllocator({ udmabufFd: fd });
22
+ };
23
+
24
+ export {
25
+ createDefaultUdmabufAllocator,
26
+ };
@@ -0,0 +1,10 @@
1
+ import { type TDmabufAllocator } from "../dmabuf-allocator-interface.js";
2
+ import { type TDmabufUdmabufAllocatorKernelInterface } from "../kernel-interface.js";
3
+ declare const createUdmabufAllocatorFactory: ({ kernelInterface }: {
4
+ kernelInterface: TDmabufUdmabufAllocatorKernelInterface;
5
+ }) => {
6
+ createUdmabufAllocator: ({ udmabufFd }: {
7
+ udmabufFd: number;
8
+ }) => TDmabufAllocator;
9
+ };
10
+ export { createUdmabufAllocatorFactory };
@@ -0,0 +1,127 @@
1
+ import { /*type TDmabufAllocator */} from "../dmabuf-allocator-interface.js";
2
+ import { createDefaultAllocationSizeDeterminer } from "../allocation-size.js";
3
+ import { /*type TDmabufHeap */} from "../dmabuf-heap/dmabuf-heap.js";
4
+ import { /*type TDmabufUdmabufAllocatorKernelInterface */} from "../kernel-interface.js";
5
+
6
+ /*type TUdmabufCreateResult = {
7
+ errno: number;
8
+ dmabufFd: undefined;
9
+ } | {
10
+ errno: undefined;
11
+ dmabufFd: number;
12
+ };*/
13
+
14
+ const UDMABUF_FLAGS_CLOEXEC = 1 << 0;
15
+ const UDMABUF_CREATE = 0x40187542n;
16
+
17
+ const F_ADD_SEALS = 1033;
18
+ const F_SEAL_SHRINK = 0x0002;
19
+
20
+ const MFD_ALLOW_SEALING = 0x0002;
21
+
22
+ const createUdmabufAllocatorFactory = ({ kernelInterface }/*: { kernelInterface: TDmabufUdmabufAllocatorKernelInterface }*/) => {
23
+
24
+ const udmabufCreate = ({ udmabufFd, memfd, size }/*: { udmabufFd: number, memfd: number; size: number }*/)/*: TUdmabufCreateResult*/ => {
25
+
26
+ const flags = UDMABUF_FLAGS_CLOEXEC;
27
+ const offset = 0n;
28
+
29
+ const udmabufCreateStruct = Buffer.alloc(24);
30
+ udmabufCreateStruct.writeUInt32LE(memfd, 0);
31
+ udmabufCreateStruct.writeUInt32LE(flags, 4);
32
+ udmabufCreateStruct.writeBigUInt64LE(offset, 8);
33
+ udmabufCreateStruct.writeBigUInt64LE(BigInt(size), 16);
34
+
35
+ const { errno: ioctlErrno, ret } = kernelInterface.ioctl({ fd: udmabufFd, request: UDMABUF_CREATE, arg: udmabufCreateStruct });
36
+ if (ioctlErrno !== undefined) {
37
+ return {
38
+ errno: ioctlErrno,
39
+ dmabufFd: undefined
40
+ };
41
+ }
42
+
43
+ const dmabufFd = Number(ret);
44
+
45
+ return {
46
+ errno: undefined,
47
+ dmabufFd
48
+ };
49
+ };
50
+
51
+ const truncateAndSealMemfd = ({ memfd, size }/*: { memfd: number; size: number }*/) => {
52
+ const { error: ftruncateError } = kernelInterface.ftruncate({ fd: memfd, length: size });
53
+ if (ftruncateError !== undefined) {
54
+ throw Error("failed to truncate memfd", { cause: ftruncateError });
55
+ }
56
+
57
+ const { errno: fcntlErrno } = kernelInterface.fcntl({ fd: memfd, cmd: F_ADD_SEALS, arg: F_SEAL_SHRINK });
58
+ if (fcntlErrno !== undefined) {
59
+ throw Error(`failed to seal memfd, errno: ${fcntlErrno}`);
60
+ }
61
+ };
62
+
63
+ const createUdmabufAllocator = ({ udmabufFd }/*: { udmabufFd: number }*/)/*: TDmabufAllocator*/ => {
64
+
65
+ const pageSize = kernelInterface.determinePageSize();
66
+ const allocationSizeDeterminer = createDefaultAllocationSizeDeterminer({ pageSize });
67
+
68
+ const determineOptimalAllocationSize/*: TDmabufHeap["determineOptimalAllocationSize"]*/ = ({ minimumSize }) => {
69
+ return allocationSizeDeterminer.determineOptimalAllocationSize({ minimumSize });
70
+ };
71
+
72
+
73
+ // eslint-disable-next-line complexity
74
+ const allocate/*: TDmabufAllocator["allocate"]*/ = ({ size }) => {
75
+
76
+ if (size <= 0) {
77
+ throw Error("size must be > 0");
78
+ }
79
+
80
+ if ((size % pageSize) !== 0) {
81
+ throw Error(`size must be a multiple of ${pageSize}`);
82
+ }
83
+
84
+ const { errno: memfdCreateErrno, memfd } = kernelInterface.memfd_create({ name: "dmabuf_alloc", flags: MFD_ALLOW_SEALING });
85
+ if (memfdCreateErrno !== undefined) {
86
+ return {
87
+ error: Error(`failed to create memfd, errno: ${memfdCreateErrno}`),
88
+ dmabufFd: undefined
89
+ };
90
+ }
91
+
92
+ try {
93
+ truncateAndSealMemfd({ memfd, size });
94
+
95
+ const { errno: createUdmabufErrno, dmabufFd } = udmabufCreate({ udmabufFd, memfd, size });
96
+
97
+ if (createUdmabufErrno !== undefined) {
98
+ return {
99
+ error: Error(`failed to create udmabuf, errno: ${createUdmabufErrno}`),
100
+ dmabufFd: undefined
101
+ };
102
+ }
103
+
104
+ return {
105
+ error: undefined,
106
+ dmabufFd
107
+ };
108
+ } finally {
109
+ kernelInterface.close({ fd: memfd });
110
+ }
111
+ };
112
+
113
+ return {
114
+ allocate,
115
+ pageSize,
116
+ determineOptimalAllocationSize
117
+ };
118
+ };
119
+
120
+ return {
121
+ createUdmabufAllocator
122
+ };
123
+ };
124
+
125
+ export {
126
+ createUdmabufAllocatorFactory
127
+ };
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.4",
2
+ "version": "0.0.5",
3
3
  "name": "@k13engineering/linux-dmabuf-allocator",
4
4
  "type": "module",
5
5
  "description": "Linux dmabuf allocator module",
@@ -11,7 +11,7 @@
11
11
  "devDependencies": {},
12
12
  "dependencies": {
13
13
  "@k13engineering/po6-ioctl": "^0.0.2",
14
- "syscall-napi": "^0.1.5"
14
+ "syscall-napi": "^0.1.6"
15
15
  },
16
16
  "publishConfig": {
17
17
  "access": "public"