1 A closure describes the types of its own signature, and does so for as long as 2 it can still be invoked. Storage shared with the surrounding call cannot be used 3 for that: it holds one entry per top level type, so a structure gets described 4 through the entry of whichever type was converted into it before and is left 5 with that type's size and alignment, which makes ffi_prep_cif() place the 6 argument wrongly and die while reading the descriptor. 7 8 The descriptors a closure synthesized belong to it rather than to the call which 9 happened to create it, since it is invoked long after that call returned. 10 11 A system library offers no entry point taking a caller defined structure, so 12 each testcase ships the source of one, compiles it with cc, and abstains when 13 no C compiler is available. 14 15 Add up the members of two structures supplied to a callback. 16 17 -- Testcase -- 18 {% 19 import * as ffi from 'ffi'; 20 21 let src = TESTFILES_PATH + '/uctestlib.c'; 22 let so = TESTFILES_PATH + '/uctestlib.so'; 23 24 if (system([ 'cc', '-shared', '-fPIC', '-o', so, src ]) != 0) 25 exit(77); 26 27 let lib = ffi.dlopen(so, false, ` 28 struct point { int x; int y; }; 29 struct wide { long a; long b; }; 30 31 int uctest_pick(int (*cmp)(struct point a, struct point b), 32 struct point a, struct point b); 33 long uctest_pick_wide(long (*cmp)(struct wide w), long a, long b); 34 `); 35 36 // A structure as an argument of a closure is what cannot be described 37 // through the storage of the enclosing call: that storage holds one entry 38 // per top level type, so the structure would be described through the 39 // entry of whichever type was converted into it before. 40 print("picked: ", lib.uctest_pick( 41 (a, b) => (a.x + a.y) - (b.x + b.y), 42 { x: 1, y: 2 }, 43 { x: 3, y: 4 }), "\n"); 44 45 print("wide: ", lib.uctest_pick_wide( 46 (w) => w.a * 1000 + w.b, 7, 3), "\n"); 47 %} 48 -- End -- 49 50 -- File uctestlib.c -- 51 struct point { 52 int x; 53 int y; 54 }; 55 56 struct wide { 57 long a; 58 long b; 59 }; 60 61 int 62 uctest_pick(int (*cmp)(struct point a, struct point b), 63 struct point a, struct point b) 64 { 65 return cmp(a, b); 66 } 67 68 long 69 uctest_pick_wide(long (*cmp)(struct wide w), long a, long b) 70 { 71 struct wide w = { a, b }; 72 73 return cmp(w); 74 } 75 -- End -- 76 77 -- Expect stdout -- 78 picked: -4 79 wide: 7003 80 -- End -- 81 82 83 Compare two structures supplied to a sorting callback. 84 85 -- Testcase -- 86 {% 87 import * as ffi from 'ffi'; 88 89 let src = TESTFILES_PATH + '/uctestlib.c'; 90 let so = TESTFILES_PATH + '/uctestlib.so'; 91 92 if (system([ 'cc', '-shared', '-fPIC', '-o', so, src ]) != 0) 93 exit(77); 94 95 let lib = ffi.dlopen(so, false, ` 96 struct point { int x; int y; }; 97 void uctest_sort(struct point *base, size_t n, 98 int (*compar)(const void *, const void *)); 99 `); 100 101 let arr = ffi.ctype('struct point[4]', 102 [{ x: 3, y: 1 }, { x: 1, y: 9 }, { x: 2, y: 0 }, { x: 0, y: 5 }]); 103 104 lib.uctest_sort(arr.ptr(), 4, 105 (a, b) => a.deref('struct point').x - b.deref('struct point').x); 106 107 let order = []; 108 109 for (let i = 0; i < 4; i++) 110 push(order, `${arr[i].x},${arr[i].y}`); 111 112 print("sorted: ", join(" ", order), "\n"); 113 %} 114 -- End -- 115 116 -- File uctestlib.c -- 117 #include <stddef.h> 118 119 struct point { 120 int x; 121 int y; 122 }; 123 124 void 125 uctest_sort(struct point *base, size_t n, 126 int (*compar)(const void *, const void *)) 127 { 128 for (size_t i = 1; i < n; i++) 129 for (size_t j = i; j > 0 && compar(&base[j - 1], &base[j]) > 0; j--) { 130 struct point t = base[j - 1]; 131 132 base[j - 1] = base[j]; 133 base[j] = t; 134 } 135 } 136 -- End -- 137 138 -- Expect stdout -- 139 sorted: 0,5 1,9 2,0 3,1 140 -- End -- 141 142 143 Invoke one closure again after the call which created it returned. 144 145 -- Testcase -- 146 {% 147 import * as ffi from 'ffi'; 148 149 let src = TESTFILES_PATH + '/uctestlib.c'; 150 let so = TESTFILES_PATH + '/uctestlib.so'; 151 152 if (system([ 'cc', '-shared', '-fPIC', '-o', so, src ]) != 0) 153 exit(77); 154 155 let lib = ffi.dlopen(so, false, ` 156 struct point { int x; int y; }; 157 void uctest_sort(struct point *base, size_t n, 158 int (*compar)(const void *, const void *)); 159 `); 160 161 let arr = ffi.ctype('struct point[3]', 162 [{ x: 2, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 2 }]); 163 164 // The closure outlives every single call below, so the descriptors it 165 // synthesized for its own argument types belong to it and cannot be 166 // released along the first of them. 167 let cmp = ffi.closure('int (*)(const void *, const void *)', 168 (a, b) => a.deref('struct point').x - b.deref('struct point').x); 169 170 let rounds = []; 171 172 for (let round = 0; round < 3; round++) { 173 lib.uctest_sort(arr.ptr(), 3, cmp); 174 175 let sorted = []; 176 177 for (let i = 0; i < 3; i++) 178 push(sorted, `${arr[i].x},${arr[i].y}`); 179 180 push(rounds, join(",", sorted)); 181 } 182 183 print("rounds: ", join(" | ", rounds), "\n"); 184 %} 185 -- End -- 186 187 -- File uctestlib.c -- 188 #include <stddef.h> 189 190 struct point { 191 int x; 192 int y; 193 }; 194 195 void 196 uctest_sort(struct point *base, size_t n, 197 int (*compar)(const void *, const void *)) 198 { 199 for (size_t i = 1; i < n; i++) 200 for (size_t j = i; j > 0 && compar(&base[j - 1], &base[j]) > 0; j--) { 201 struct point t = base[j - 1]; 202 203 base[j - 1] = base[j]; 204 base[j] = t; 205 } 206 } 207 -- End -- 208 209 -- Expect stdout -- 210 rounds: 0,1,1,2,2,0 | 0,1,1,2,2,0 | 0,1,1,2,2,0 211 -- End --
This page was automatically generated by LXR 0.3.1. • OpenWrt