/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2021, Ideas on Board Oy * * drm.h - DRM/KMS Helpers */ #pragma once #include <array> #include <list> #include <map> #include <memory> #include <stdint.h> #include <string> #include <vector> #include <libcamera/base/signal.h> #include <libcamera/base/span.h> #include <libdrm/drm.h> #include <xf86drm.h> #include <xf86drmMode.h> namespace libcamera { class FrameBuffer; class PixelFormat; class Size; } /* namespace libcamera */ namespace DRM { class Device; class Plane; class Property; class PropertyValue; class Object { public: enum Type { TypeCrtc = DRM_MODE_OBJECT_CRTC, TypeConnector = DRM_MODE_OBJECT_CONNECTOR, TypeEncoder = DRM_MODE_OBJECT_ENCODER, TypeMode = DRM_MODE_OBJECT_MODE, TypeProperty = DRM_MODE_OBJECT_PROPERTY, TypeFb = DRM_MODE_OBJECT_FB, TypeBlob = DRM_MODE_OBJECT_BLOB, TypePlane = DRM_MODE_OBJECT_PLANE, TypeAny = DRM_MODE_OBJECT_ANY, }; Object(Device *dev, uint32_t id, Type type); virtual ~Object(); Device *device() const { return dev_; } uint32_t id() const { return id_; } Type type() const { return type_; } const Property *property(const std::string &name) const; const PropertyValue *propertyValue(const std::string &name) const; const std::vector<PropertyValue> &properties() const { return properties_; } protected: virtual int setup() { return 0; } uint32_t id_; private: friend Device; Device *dev_; Type type_; std::vector<PropertyValue> properties_; }; class Property : public Object { public: enum Type { TypeUnknown = 0, TypeRange, TypeEnum, TypeBlob, TypeBitmask, TypeObject, TypeSignedRange, }; Property(Device *dev, drmModePropertyRes *property); Type type() const { return type_; } const std::string &name() const { return name_; } bool isImmutable() const { return flags_ & DRM_MODE_PROP_IMMUTABLE; } const std::vector<uint64_t> values() const { return values_; } const std::map<uint32_t, std::string> &enums() const { return enums_; } const std::vector<uint32_t> blobs() const { return blobs_; } private: Type type_; std::string name_; uint32_t flags_; std::vector<uint64_t> values_; std::map<uint32_t, std::string> enums_; std::vector<uint32_t> blobs_; }; class PropertyValue { public: PropertyValue(uint32_t id, uint64_t value) : id_(id), value_(value) { } uint32_t id() const { return id_; } uint32_t value() const { return value_; } private: uint32_t id_; uint64_t value_; }; class Blob : public Object { public: Blob(Device *dev, const libcamera::Span<const uint8_t> &data); ~Blob(); bool isValid() const { return id() != 0; } }; class Mode : public drmModeModeInfo { public: Mode(const drmModeModeInfo &mode); std::unique_ptr<Blob> toBlob(Device *dev) const; }; class Crtc : public Object { public: Crtc(Device *dev, const drmModeCrtc *crtc, unsigned int index); unsigned int index() const { return index_; } const std::vector<const Plane *> &planes() const { return planes_; } private: friend Device; unsigned int index_; std::vector<const Plane *> planes_; }; class Encoder : public Object { public: Encoder(Device *dev, const drmModeEncoder *encoder); uint32_t type() const { return type_; } const std::vector<const Crtc *> &possibleCrtcs() const { return possibleCrtcs_; } private: uint32_t type_; std::vector<const Crtc *> possibleCrtcs_; }; class Connector : public Object { public: enum Status { Connected, Disconnected, Unknown, }; Connector(Device *dev, const drmModeConnector *connector); uint32_t type() const { return type_; } const std::string &name() const { return name_; } Status status() const { return status_; } const std::vector<const Encoder *> &encoders() const { return encoders_; } const std::vector<Mode> &modes() const { return modes_; } private: uint32_t type_; std::string name_; Status status_; std::vector<const Encoder *> encoders_; std::vector<Mode> modes_; }; class Plane : public Object { public: enum Type { TypeOverlay, TypePrimary, TypeCursor, }; Plane(Device *dev, const drmModePlane *plane); Type type() const { return type_; } const std::vector<uint32_t> &formats() const { return formats_; } const std::vector<const Crtc *> &possibleCrtcs() const { return possibleCrtcs_; } bool supportsFormat(const libcamera::PixelFormat &format) const; protected: int setup() override; private: friend class Device; Type type_; std::vector<uint32_t> formats_; std::vector<const Crtc *> possibleCrtcs_; uint32_t possibleCrtcsMask_; }; class FrameBuffer : public Object { public: struct Plane { uint32_t handle; }; ~FrameBuffer(); private: friend class Device; FrameBuffer(Device *dev); std::map<int, Plane> planes_; }; class AtomicRequest { public: enum Flags { FlagAllowModeset = (1 << 0), FlagAsync = (1 << 1), FlagTestOnly = (1 << 2), }; AtomicRequest(Device *dev); ~AtomicRequest(); Device *device() const { return dev_; } bool isValid() const { return valid_; } int addProperty(const Object *object, const std::string &property, uint64_t value); int addProperty(const Object *object, const std::string &property, std::unique_ptr<Blob> blob); int commit(unsigned int flags = 0); private: AtomicRequest(const AtomicRequest &) = delete; AtomicRequest(const AtomicRequest &&) = delete; AtomicRequest &operator=(const AtomicRequest &) = delete; AtomicRequest &operator=(const AtomicRequest &&) = delete; int addProperty(uint32_t object, uint32_t property, uint64_t value); Device *dev_; bool valid_; drmModeAtomicReq *request_; std::list<std::unique_ptr<Blob>> blobs_; }; class Device { public: Device(); ~Device(); int init(); int fd() const { return fd_; } const std::list<Crtc> &crtcs() const { return crtcs_; } const std::list<Encoder> &encoders() const { return encoders_; } const std::list<Connector> &connectors() const { return connectors_; } const std::list<Plane> &planes() const { return planes_; } const std::list<Property> &properties() const { return properties_; } const Object *object(uint32_t id); std::unique_ptr<FrameBuffer> createFrameBuffer( const libcamera::FrameBuffer &buffer, const libcamera::PixelFormat &format, const libcamera::Size &size, const std::array<uint32_t, 4> &strides); libcamera::Signal<AtomicRequest *> requestComplete; private: Device(const Device &) = delete; Device(const Device &&) = delete; Device &operator=(const Device &) = delete; Device &operator=(const Device &&) = delete; int openCard(); int getResources(); void drmEvent(); static void pageFlipComplete(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data); int fd_; std::list<Crtc> crtcs_; std::list<Encoder> encoders_; std::list<Connector> connectors_; std::list<Plane> planes_; std::list<Property> properties_; std::map<uint32_t, Object *> objects_; }; } /* namespace DRM */ >128</a> <a id='n129' href='#n129'>129</a> <a id='n130' href='#n130'>130</a> <a id='n131' href='#n131'>131</a> <a id='n132' href='#n132'>132</a> <a id='n133' href='#n133'>133</a> <a id='n134' href='#n134'>134</a> <a id='n135' href='#n135'>135</a> <a id='n136' href='#n136'>136</a> <a id='n137' href='#n137'>137</a> <a id='n138' href='#n138'>138</a> <a id='n139' href='#n139'>139</a> <a id='n140' href='#n140'>140</a> <a id='n141' href='#n141'>141</a> <a id='n142' href='#n142'>142</a> <a id='n143' href='#n143'>143</a> <a id='n144' href='#n144'>144</a> <a id='n145' href='#n145'>145</a> <a id='n146' href='#n146'>146</a> <a id='n147' href='#n147'>147</a> <a id='n148' href='#n148'>148</a> <a id='n149' href='#n149'>149</a> <a id='n150' href='#n150'>150</a> <a id='n151' href='#n151'>151</a> <a id='n152' href='#n152'>152</a> <a id='n153' href='#n153'>153</a> <a id='n154' href='#n154'>154</a> <a id='n155' href='#n155'>155</a> <a id='n156' href='#n156'>156</a> <a id='n157' href='#n157'>157</a> <a id='n158' href='#n158'>158</a> <a id='n159' href='#n159'>159</a> <a id='n160' href='#n160'>160</a> <a id='n161' href='#n161'>161</a> <a id='n162' href='#n162'>162</a> <a id='n163' href='#n163'>163</a> <a id='n164' href='#n164'>164</a> <a id='n165' href='#n165'>165</a> <a id='n166' href='#n166'>166</a> <a id='n167' href='#n167'>167</a> <a id='n168' href='#n168'>168</a> <a id='n169' href='#n169'>169</a> <a id='n170' href='#n170'>170</a> <a id='n171' href='#n171'>171</a> <a id='n172' href='#n172'>172</a> <a id='n173' href='#n173'>173</a> <a id='n174' href='#n174'>174</a> <a id='n175' href='#n175'>175</a> <a id='n176' href='#n176'>176</a> <a id='n177' href='#n177'>177</a> <a id='n178' href='#n178'>178</a> <a id='n179' href='#n179'>179</a> <a id='n180' href='#n180'>180</a> <a id='n181' href='#n181'>181</a> <a id='n182' href='#n182'>182</a> <a id='n183' href='#n183'>183</a> <a id='n184' href='#n184'>184</a> <a id='n185' href='#n185'>185</a> <a id='n186' href='#n186'>186</a> <a id='n187' href='#n187'>187</a> <a id='n188' href='#n188'>188</a> <a id='n189' href='#n189'>189</a> <a id='n190' href='#n190'>190</a> <a id='n191' href='#n191'>191</a> <a id='n192' href='#n192'>192</a> <a id='n193' href='#n193'>193</a> <a id='n194' href='#n194'>194</a> <a id='n195' href='#n195'>195</a> <a id='n196' href='#n196'>196</a> <a id='n197' href='#n197'>197</a> <a id='n198' href='#n198'>198</a> <a id='n199' href='#n199'>199</a> <a id='n200' href='#n200'>200</a> <a id='n201' href='#n201'>201</a> <a id='n202' href='#n202'>202</a> <a id='n203' href='#n203'>203</a> <a id='n204' href='#n204'>204</a> <a id='n205' href='#n205'>205</a> <a id='n206' href='#n206'>206</a> <a id='n207' href='#n207'>207</a> <a id='n208' href='#n208'>208</a> <a id='n209' href='#n209'>209</a> <a id='n210' href='#n210'>210</a> <a id='n211' href='#n211'>211</a> <a id='n212' href='#n212'>212</a> <a id='n213' href='#n213'>213</a> <a id='n214' href='#n214'>214</a> <a id='n215' href='#n215'>215</a> <a id='n216' href='#n216'>216</a> <a id='n217' href='#n217'>217</a> <a id='n218' href='#n218'>218</a> <a id='n219' href='#n219'>219</a> <a id='n220' href='#n220'>220</a> <a id='n221' href='#n221'>221</a> <a id='n222' href='#n222'>222</a> <a id='n223' href='#n223'>223</a> <a id='n224' href='#n224'>224</a> <a id='n225' href='#n225'>225</a> <a id='n226' href='#n226'>226</a> <a id='n227' href='#n227'>227</a> <a id='n228' href='#n228'>228</a> <a id='n229' href='#n229'>229</a> <a id='n230' href='#n230'>230</a> <a id='n231' href='#n231'>231</a> <a id='n232' href='#n232'>232</a> <a id='n233' href='#n233'>233</a> <a id='n234' href='#n234'>234</a> <a id='n235' href='#n235'>235</a> <a id='n236' href='#n236'>236</a> <a id='n237' href='#n237'>237</a> <a id='n238' href='#n238'>238</a> <a id='n239' href='#n239'>239</a> <a id='n240' href='#n240'>240</a> <a id='n241' href='#n241'>241</a> <a id='n242' href='#n242'>242</a> <a id='n243' href='#n243'>243</a> <a id='n244' href='#n244'>244</a> <a id='n245' href='#n245'>245</a> <a id='n246' href='#n246'>246</a> <a id='n247' href='#n247'>247</a> <a id='n248' href='#n248'>248</a> <a id='n249' href='#n249'>249</a> <a id='n250' href='#n250'>250</a> <a id='n251' href='#n251'>251</a> <a id='n252' href='#n252'>252</a> <a id='n253' href='#n253'>253</a> <a id='n254' href='#n254'>254</a> <a id='n255' href='#n255'>255</a> <a id='n256' href='#n256'>256</a> <a id='n257' href='#n257'>257</a> <a id='n258' href='#n258'>258</a> <a id='n259' href='#n259'>259</a> <a id='n260' href='#n260'>260</a> <a id='n261' href='#n261'>261</a> <a id='n262' href='#n262'>262</a> <a id='n263' href='#n263'>263</a> <a id='n264' href='#n264'>264</a> <a id='n265' href='#n265'>265</a> <a id='n266' href='#n266'>266</a> <a id='n267' href='#n267'>267</a> <a id='n268' href='#n268'>268</a> <a id='n269' href='#n269'>269</a> <a id='n270' href='#n270'>270</a> <a id='n271' href='#n271'>271</a> <a id='n272' href='#n272'>272</a> <a id='n273' href='#n273'>273</a> <a id='n274' href='#n274'>274</a> <a id='n275' href='#n275'>275</a> <a id='n276' href='#n276'>276</a> <a id='n277' href='#n277'>277</a> <a id='n278' href='#n278'>278</a> <a id='n279' href='#n279'>279</a> <a id='n280' href='#n280'>280</a> <a id='n281' href='#n281'>281</a> <a id='n282' href='#n282'>282</a> <a id='n283' href='#n283'>283</a> <a id='n284' href='#n284'>284</a> <a id='n285' href='#n285'>285</a> <a id='n286' href='#n286'>286</a> <a id='n287' href='#n287'>287</a> <a id='n288' href='#n288'>288</a> <a id='n289' href='#n289'>289</a> <a id='n290' href='#n290'>290</a> <a id='n291' href='#n291'>291</a> <a id='n292' href='#n292'>292</a> <a id='n293' href='#n293'>293</a> <a id='n294' href='#n294'>294</a> <a id='n295' href='#n295'>295</a> <a id='n296' href='#n296'>296</a> <a id='n297' href='#n297'>297</a> <a id='n298' href='#n298'>298</a> <a id='n299' href='#n299'>299</a> <a id='n300' href='#n300'>300</a> <a id='n301' href='#n301'>301</a> <a id='n302' href='#n302'>302</a> <a id='n303' href='#n303'>303</a> <a id='n304' href='#n304'>304</a> <a id='n305' href='#n305'>305</a> <a id='n306' href='#n306'>306</a> <a id='n307' href='#n307'>307</a> <a id='n308' href='#n308'>308</a> <a id='n309' href='#n309'>309</a> <a id='n310' href='#n310'>310</a> <a id='n311' href='#n311'>311</a> <a id='n312' href='#n312'>312</a> <a id='n313' href='#n313'>313</a> <a id='n314' href='#n314'>314</a> <a id='n315' href='#n315'>315</a> <a id='n316' href='#n316'>316</a> <a id='n317' href='#n317'>317</a> <a id='n318' href='#n318'>318</a> <a id='n319' href='#n319'>319</a> <a id='n320' href='#n320'>320</a> <a id='n321' href='#n321'>321</a> <a id='n322' href='#n322'>322</a> <a id='n323' href='#n323'>323</a> <a id='n324' href='#n324'>324</a> <a id='n325' href='#n325'>325</a> <a id='n326' href='#n326'>326</a> <a id='n327' href='#n327'>327</a> <a id='n328' href='#n328'>328</a> <a id='n329' href='#n329'>329</a> <a id='n330' href='#n330'>330</a> <a id='n331' href='#n331'>331</a> <a id='n332' href='#n332'>332</a> <a id='n333' href='#n333'>333</a> <a id='n334' href='#n334'>334</a> <a id='n335' href='#n335'>335</a> <a id='n336' href='#n336'>336</a> <a id='n337' href='#n337'>337</a> <a id='n338' href='#n338'>338</a> <a id='n339' href='#n339'>339</a> <a id='n340' href='#n340'>340</a> <a id='n341' href='#n341'>341</a> <a id='n342' href='#n342'>342</a> </pre></td> <td class='lines'><pre><code><span class="hl com">/* SPDX-License-Identifier: GPL-2.0-or-later */</span> <span class="hl com">/*</span> <span class="hl com"> * Copyright (C) 2021, Google Inc.</span> <span class="hl com"> *</span> <span class="hl com"> * fence.cpp - Fence test</span> <span class="hl com"> */</span> <span class="hl ppc">#include <iostream></span> <span class="hl ppc">#include <memory></span> <span class="hl ppc">#include <sys/eventfd.h></span> <span class="hl ppc">#include <unistd.h></span> <span class="hl ppc">#include <libcamera/base/event_dispatcher.h></span> <span class="hl ppc">#include <libcamera/base/thread.h></span> <span class="hl ppc">#include <libcamera/base/timer.h></span> <span class="hl ppc">#include <libcamera/base/unique_fd.h></span> <span class="hl ppc">#include <libcamera/base/utils.h></span> <span class="hl ppc">#include <libcamera/fence.h></span> <span class="hl ppc">#include <libcamera/framebuffer_allocator.h></span> <span class="hl ppc">#include</span> <span class="hl pps">"camera_test.h"</span><span class="hl ppc"></span> <span class="hl ppc">#include</span> <span class="hl pps">"test.h"</span><span class="hl ppc"></span> <span class="hl kwa">using namespace</span> libcamera<span class="hl opt">;</span> <span class="hl kwa">using namespace</span> std<span class="hl opt">;</span> <span class="hl kwa">using namespace</span> <span class="hl kwc">std</span><span class="hl opt">::</span>chrono_literals<span class="hl opt">;</span> <span class="hl kwc">class</span> FenceTest <span class="hl opt">:</span> <span class="hl kwc">public</span> CameraTest<span class="hl opt">,</span> <span class="hl kwc">public</span> Test <span class="hl opt">{</span> <span class="hl kwc">public</span><span class="hl opt">:</span> <span class="hl kwd">FenceTest</span><span class="hl opt">();</span> <span class="hl kwc">protected</span><span class="hl opt">:</span> <span class="hl kwb">int</span> <span class="hl kwd">init</span><span class="hl opt">()</span> override<span class="hl opt">;</span> <span class="hl kwb">int</span> <span class="hl kwd">run</span><span class="hl opt">()</span> override<span class="hl opt">;</span> <span class="hl kwc">private</span><span class="hl opt">:</span> <span class="hl kwb">int</span> <span class="hl kwd">validateExpiredRequest</span><span class="hl opt">(</span>Request <span class="hl opt">*</span>request<span class="hl opt">);</span> <span class="hl kwb">int</span> <span class="hl kwd">validateRequest</span><span class="hl opt">(</span>Request <span class="hl opt">*</span>request<span class="hl opt">);</span> <span class="hl kwb">void</span> <span class="hl kwd">requestComplete</span><span class="hl opt">(</span>Request <span class="hl opt">*</span>request<span class="hl opt">);</span> <span class="hl kwb">void</span> <span class="hl kwd">requestRequeue</span><span class="hl opt">(</span>Request <span class="hl opt">*</span>request<span class="hl opt">);</span> <span class="hl kwb">void</span> <span class="hl kwd">signalFence</span><span class="hl opt">();</span> <span class="hl kwc">std</span><span class="hl opt">::</span>unique_ptr<span class="hl opt"><</span>Fence<span class="hl opt">></span> fence_<span class="hl opt">;</span> EventDispatcher <span class="hl opt">*</span>dispatcher_<span class="hl opt">;</span> UniqueFD eventFd_<span class="hl opt">;</span> UniqueFD eventFd2_<span class="hl opt">;</span> Timer fenceTimer_<span class="hl opt">;</span> <span class="hl kwc">std</span><span class="hl opt">::</span>vector<span class="hl opt"><</span><span class="hl kwc">std</span><span class="hl opt">::</span>unique_ptr<span class="hl opt"><</span>Request<span class="hl opt">>></span> requests_<span class="hl opt">;</span> <span class="hl kwc">std</span><span class="hl opt">::</span>unique_ptr<span class="hl opt"><</span>CameraConfiguration<span class="hl opt">></span> config_<span class="hl opt">;</span> <span class="hl kwc">std</span><span class="hl opt">::</span>unique_ptr<span class="hl opt"><</span>FrameBufferAllocator<span class="hl opt">></span> allocator_<span class="hl opt">;</span> Stream <span class="hl opt">*</span>stream_<span class="hl opt">;</span> <span class="hl kwb">bool</span> expectedCompletionResult_ <span class="hl opt">=</span> <span class="hl kwa">true</span><span class="hl opt">;</span> <span class="hl kwb">bool</span> setFence_ <span class="hl opt">=</span> <span class="hl kwa">true</span><span class="hl opt">;</span> <span class="hl kwb">unsigned int</span> completedRequest_<span class="hl opt">;</span> <span class="hl kwb">unsigned int</span> signalledRequestId_<span class="hl opt">;</span> <span class="hl kwb">unsigned int</span> expiredRequestId_<span class="hl opt">;</span> <span class="hl kwb">unsigned int</span> nbuffers_<span class="hl opt">;</span> <span class="hl kwb">int</span> efd2_<span class="hl opt">;</span> <span class="hl kwb">int</span> efd_<span class="hl opt">;</span> <span class="hl opt">};</span> <span class="hl kwc">FenceTest</span><span class="hl opt">::</span><span class="hl kwd">FenceTest</span><span class="hl opt">()</span> <span class="hl opt">:</span> <span class="hl kwd">CameraTest</span><span class="hl opt">(</span><span class="hl str">"platform/vimc.0 Sensor B"</span><span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl opt">}</span> <span class="hl kwb">int</span> <span class="hl kwc">FenceTest</span><span class="hl opt">::</span><span class="hl kwd">init</span><span class="hl opt">()</span> <span class="hl opt">{</span> <span class="hl com">/* Make sure the CameraTest constructor succeeded. */</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>status_ <span class="hl opt">!=</span> TestPass<span class="hl opt">)</span> <span class="hl kwa">return</span> status_<span class="hl opt">;</span> dispatcher_ <span class="hl opt">=</span> <span class="hl kwc">Thread</span><span class="hl opt">::</span><span class="hl kwd">current</span><span class="hl opt">()-></span><span class="hl kwd">eventDispatcher</span><span class="hl opt">();</span> <span class="hl com">/*</span> <span class="hl com"> * Create two eventfds to model the fences. This is enough to support the</span> <span class="hl com"> * needs of libcamera which only needs to wait for read events through</span> <span class="hl com"> * poll(). Once native support for fences will be available in the</span> <span class="hl com"> * backend kernel APIs this will need to be replaced by a sw_sync fence,</span> <span class="hl com"> * but that requires debugfs.</span> <span class="hl com"> */</span> eventFd_ <span class="hl opt">=</span> <span class="hl kwd">UniqueFD</span><span class="hl opt">(</span><span class="hl kwd">eventfd</span><span class="hl opt">(</span><span class="hl num">0</span><span class="hl opt">,</span> EFD_CLOEXEC <span class="hl opt">|</span> EFD_NONBLOCK<span class="hl opt">));</span> eventFd2_ <span class="hl opt">=</span> <span class="hl kwd">UniqueFD</span><span class="hl opt">(</span><span class="hl kwd">eventfd</span><span class="hl opt">(</span><span class="hl num">0</span><span class="hl opt">,</span> EFD_CLOEXEC <span class="hl opt">|</span> EFD_NONBLOCK<span class="hl opt">));</span> <span class="hl kwa">if</span> <span class="hl opt">(!</span>eventFd_<span class="hl opt">.</span><span class="hl kwd">isValid</span><span class="hl opt">() || !</span>eventFd2_<span class="hl opt">.</span><span class="hl kwd">isValid</span><span class="hl opt">()) {</span> cerr <span class="hl opt"><<</span> <span class="hl str">"Unable to create eventfd"</span> <span class="hl opt"><<</span> endl<span class="hl opt">;</span> <span class="hl kwa">return</span> TestFail<span class="hl opt">;</span> <span class="hl opt">}</span> efd_ <span class="hl opt">=</span> eventFd_<span class="hl opt">.</span><span class="hl kwd">get</span><span class="hl opt">();</span> efd2_ <span class="hl opt">=</span> eventFd2_<span class="hl opt">.</span><span class="hl kwd">get</span><span class="hl opt">();</span> config_ <span class="hl opt">=</span> camera_<span class="hl opt">-></span><span class="hl kwd">generateConfiguration</span><span class="hl opt">({</span> <span class="hl kwc">StreamRole</span><span class="hl opt">::</span>Viewfinder <span class="hl opt">});</span> <span class="hl kwa">if</span> <span class="hl opt">(!</span>config_ <span class="hl opt">||</span> config_<span class="hl opt">-></span><span class="hl kwd">size</span><span class="hl opt">() !=</span> <span class="hl num">1</span><span class="hl opt">) {</span> cerr <span class="hl opt"><<</span> <span class="hl str">"Failed to generate default configuration"</span> <span class="hl opt"><<</span> endl<span class="hl opt">;</span> <span class="hl kwa">return</span> TestFail<span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>camera_<span class="hl opt">-></span><span class="hl kwd">acquire</span><span class="hl opt">()) {</span> cerr <span class="hl opt"><<</span> <span class="hl str">"Failed to acquire the camera"</span> <span class="hl opt"><<</span> endl<span class="hl opt">;</span> <span class="hl kwa">return</span> TestFail<span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>camera_<span class="hl opt">-></span><span class="hl kwd">configure</span><span class="hl opt">(</span>config_<span class="hl opt">.</span><span class="hl kwd">get</span><span class="hl opt">())) {</span> cerr <span class="hl opt"><<</span> <span class="hl str">"Failed to set default configuration"</span> <span class="hl opt"><<</span> endl<span class="hl opt">;</span> <span class="hl kwa">return</span> TestFail<span class="hl opt">;</span> <span class="hl opt">}</span> StreamConfiguration <span class="hl opt">&</span>cfg <span class="hl opt">=</span> config_<span class="hl opt">-></span><span class="hl kwd">at</span><span class="hl opt">(</span><span class="hl num">0</span><span class="hl opt">);</span> stream_ <span class="hl opt">=</span> cfg<span class="hl opt">.</span><span class="hl kwd">stream</span><span class="hl opt">();</span> allocator_ <span class="hl opt">=</span> <span class="hl kwc">std</span><span class="hl opt">::</span>make_unique<span class="hl opt"><</span>FrameBufferAllocator<span class="hl opt">>(</span>camera_<span class="hl opt">);</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>allocator_<span class="hl opt">-></span><span class="hl kwd">allocate</span><span class="hl opt">(</span>stream_<span class="hl opt">) <</span> <span class="hl num">0</span><span class="hl opt">)</span> <span class="hl kwa">return</span> TestFail<span class="hl opt">;</span> nbuffers_ <span class="hl opt">=</span> allocator_<span class="hl opt">-></span><span class="hl kwd">buffers</span><span class="hl opt">(</span>stream_<span class="hl opt">).</span><span class="hl kwd">size</span><span class="hl opt">();</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>nbuffers_ <span class="hl opt"><</span> <span class="hl num">2</span><span class="hl opt">) {</span> cerr <span class="hl opt"><<</span> <span class="hl str">"Not enough buffers available"</span> <span class="hl opt"><<</span> endl<span class="hl opt">;</span> <span class="hl kwa">return</span> TestFail<span class="hl opt">;</span> <span class="hl opt">}</span> signalledRequestId_ <span class="hl opt">=</span> nbuffers_ <span class="hl opt">-</span> <span class="hl num">2</span><span class="hl opt">;</span> expiredRequestId_ <span class="hl opt">=</span> nbuffers_ <span class="hl opt">-</span> <span class="hl num">1</span><span class="hl opt">;</span> <span class="hl kwa">return</span> TestPass<span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwb">int</span> <span class="hl kwc">FenceTest</span><span class="hl opt">::</span><span class="hl kwd">validateExpiredRequest</span><span class="hl opt">(</span>Request <span class="hl opt">*</span>request<span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl com">/* The last request is expected to fail. */</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>request<span class="hl opt">-></span><span class="hl kwd">status</span><span class="hl opt">() !=</span> <span class="hl kwc">Request</span><span class="hl opt">::</span>RequestCancelled<span class="hl opt">) {</span> cerr <span class="hl opt"><<</span> <span class="hl str">"The last request should have failed: "</span> <span class="hl opt"><<</span> endl<span class="hl opt">;</span> <span class="hl kwa">return</span> TestFail<span class="hl opt">;</span> <span class="hl opt">}</span> FrameBuffer <span class="hl opt">*</span>buffer <span class="hl opt">=</span> request<span class="hl opt">-></span><span class="hl kwd">buffers</span><span class="hl opt">().</span><span class="hl kwd">begin</span><span class="hl opt">()-></span>second<span class="hl opt">;</span> <span class="hl kwc">std</span><span class="hl opt">::</span>unique_ptr<span class="hl opt"><</span>Fence<span class="hl opt">></span> fence <span class="hl opt">=</span> buffer<span class="hl opt">-></span><span class="hl kwd">releaseFence</span><span class="hl opt">();</span> <span class="hl kwa">if</span> <span class="hl opt">(!</span>fence<span class="hl opt">) {</span> cerr <span class="hl opt"><<</span> <span class="hl str">"The expired fence should be present"</span> <span class="hl opt"><<</span> endl<span class="hl opt">;</span> <span class="hl kwa">return</span> TestFail<span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwa">if</span> <span class="hl opt">(!</span>fence<span class="hl opt">-></span><span class="hl kwd">isValid</span><span class="hl opt">()) {</span> cerr <span class="hl opt"><<</span> <span class="hl str">"The expired fence should be valid"</span> <span class="hl opt"><<</span> endl<span class="hl opt">;</span> <span class="hl kwa">return</span> TestFail<span class="hl opt">;</span> <span class="hl opt">}</span> UniqueFD fd <span class="hl opt">=</span> fence<span class="hl opt">-></span><span class="hl kwd">release</span><span class="hl opt">();</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>fd<span class="hl opt">.</span><span class="hl kwd">get</span><span class="hl opt">() !=</span> efd_<span class="hl opt">) {</span> cerr <span class="hl opt"><<</span> <span class="hl str">"The expired fence file descriptor should not change"</span> <span class="hl opt"><<</span> endl<span class="hl opt">;</span> <span class="hl kwa">return</span> TestFail<span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwa">return</span> TestPass<span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwb">int</span> <span class="hl kwc">FenceTest</span><span class="hl opt">::</span><span class="hl kwd">validateRequest</span><span class="hl opt">(</span>Request <span class="hl opt">*</span>request<span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl kwb">uint64_t</span> cookie <span class="hl opt">=</span> request<span class="hl opt">-></span><span class="hl kwd">cookie</span><span class="hl opt">();</span> <span class="hl com">/* All requests but the last are expected to succeed. */</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>request<span class="hl opt">-></span><span class="hl kwd">status</span><span class="hl opt">() !=</span> <span class="hl kwc">Request</span><span class="hl opt">::</span>RequestComplete<span class="hl opt">) {</span> cerr <span class="hl opt"><<</span> <span class="hl str">"Unexpected request failure: "</span> <span class="hl opt"><<</span> cookie <span class="hl opt"><<</span> endl<span class="hl opt">;</span> <span class="hl kwa">return</span> TestFail<span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl com">/* A successfully completed request should have the Fence closed. */</span> <span class="hl kwb">const</span> <span class="hl kwc">Request</span><span class="hl opt">::</span>BufferMap <span class="hl opt">&</span>buffers <span class="hl opt">=</span> request<span class="hl opt">-></span><span class="hl kwd">buffers</span><span class="hl opt">();</span> FrameBuffer <span class="hl opt">*</span>buffer <span class="hl opt">=</span> buffers<span class="hl opt">.</span><span class="hl kwd">begin</span><span class="hl opt">()-></span>second<span class="hl opt">;</span> <span class="hl kwc">std</span><span class="hl opt">::</span>unique_ptr<span class="hl opt"><</span>Fence<span class="hl opt">></span> bufferFence <span class="hl opt">=</span> buffer<span class="hl opt">-></span><span class="hl kwd">releaseFence</span><span class="hl opt">();</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>bufferFence<span class="hl opt">) {</span> cerr <span class="hl opt"><<</span> <span class="hl str">"Unexpected valid fence in completed request"</span> <span class="hl opt"><<</span> endl<span class="hl opt">;</span> <span class="hl kwa">return</span> TestFail<span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwa">return</span> TestPass<span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwb">void</span> <span class="hl kwc">FenceTest</span><span class="hl opt">::</span><span class="hl kwd">requestRequeue</span><span class="hl opt">(</span>Request <span class="hl opt">*</span>request<span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl kwb">const</span> <span class="hl kwc">Request</span><span class="hl opt">::</span>BufferMap <span class="hl opt">&</span>buffers <span class="hl opt">=</span> request<span class="hl opt">-></span><span class="hl kwd">buffers</span><span class="hl opt">();</span> <span class="hl kwb">const</span> Stream <span class="hl opt">*</span>stream <span class="hl opt">=</span> buffers<span class="hl opt">.</span><span class="hl kwd">begin</span><span class="hl opt">()-></span>first<span class="hl opt">;</span> FrameBuffer <span class="hl opt">*</span>buffer <span class="hl opt">=</span> buffers<span class="hl opt">.</span><span class="hl kwd">begin</span><span class="hl opt">()-></span>second<span class="hl opt">;</span> <span class="hl kwb">uint64_t</span> cookie <span class="hl opt">=</span> request<span class="hl opt">-></span><span class="hl kwd">cookie</span><span class="hl opt">();</span> request<span class="hl opt">-></span><span class="hl kwd">reuse</span><span class="hl opt">();</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>cookie <span class="hl opt">==</span> signalledRequestId_ <span class="hl opt">&&</span> setFence_<span class="hl opt">) {</span> <span class="hl com">/*</span> <span class="hl com"> * The second time this request is queued add a fence to it.</span> <span class="hl com"> *</span> <span class="hl com"> * The main loop signals it by using a timer to write to the</span> <span class="hl com"> * efd2_ file descriptor before the fence expires.</span> <span class="hl com"> */</span> <span class="hl kwc">std</span><span class="hl opt">::</span>unique_ptr<span class="hl opt"><</span>Fence<span class="hl opt">></span> fence <span class="hl opt">=</span> <span class="hl kwc">std</span><span class="hl opt">::</span>make_unique<span class="hl opt"><</span>Fence<span class="hl opt">>(</span><span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwd">move</span><span class="hl opt">(</span>eventFd2_<span class="hl opt">));</span> request<span class="hl opt">-></span><span class="hl kwd">addBuffer</span><span class="hl opt">(</span>stream<span class="hl opt">,</span> buffer<span class="hl opt">,</span> <span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwd">move</span><span class="hl opt">(</span>fence<span class="hl opt">));</span> <span class="hl opt">}</span> <span class="hl kwa">else</span> <span class="hl opt">{</span> <span class="hl com">/* All the other requests continue to operate without fences. */</span> request<span class="hl opt">-></span><span class="hl kwd">addBuffer</span><span class="hl opt">(</span>stream<span class="hl opt">,</span> buffer<span class="hl opt">);</span> <span class="hl opt">}</span> camera_<span class="hl opt">-></span><span class="hl kwd">queueRequest</span><span class="hl opt">(</span>request<span class="hl opt">);</span> <span class="hl opt">}</span> <span class="hl kwb">void</span> <span class="hl kwc">FenceTest</span><span class="hl opt">::</span><span class="hl kwd">requestComplete</span><span class="hl opt">(</span>Request <span class="hl opt">*</span>request<span class="hl opt">)</span> <span class="hl opt">{</span> <span class="hl kwb">uint64_t</span> cookie <span class="hl opt">=</span> request<span class="hl opt">-></span><span class="hl kwd">cookie</span><span class="hl opt">();</span> completedRequest_ <span class="hl opt">=</span> cookie<span class="hl opt">;</span> <span class="hl com">/*</span> <span class="hl com"> * The last request is expected to fail as its fence has not been</span> <span class="hl com"> * signaled.</span> <span class="hl com"> *</span> <span class="hl com"> * Validate the fence status but do not re-queue it.</span> <span class="hl com"> */</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>cookie <span class="hl opt">==</span> expiredRequestId_<span class="hl opt">) {</span> <span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwd">validateExpiredRequest</span><span class="hl opt">(</span>request<span class="hl opt">) !=</span> TestPass<span class="hl opt">)</span> expectedCompletionResult_ <span class="hl opt">=</span> <span class="hl kwa">false</span><span class="hl opt">;</span> dispatcher_<span class="hl opt">-></span><span class="hl kwd">interrupt</span><span class="hl opt">();</span> <span class="hl kwa">return</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl com">/* Validate all requests but the last. */</span> <span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwd">validateRequest</span><span class="hl opt">(</span>request<span class="hl opt">) !=</span> TestPass<span class="hl opt">) {</span> expectedCompletionResult_ <span class="hl opt">=</span> <span class="hl kwa">false</span><span class="hl opt">;</span> dispatcher_<span class="hl opt">-></span><span class="hl kwd">interrupt</span><span class="hl opt">();</span> <span class="hl kwa">return</span><span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwd">requestRequeue</span><span class="hl opt">(</span>request<span class="hl opt">);</span> <span class="hl com">/*</span> <span class="hl com"> * Interrupt the dispatcher to return control to the main loop and</span> <span class="hl com"> * activate the fenceTimer.</span> <span class="hl com"> */</span> dispatcher_<span class="hl opt">-></span><span class="hl kwd">interrupt</span><span class="hl opt">();</span> <span class="hl opt">}</span> <span class="hl com">/* Callback to signal a fence waiting on the eventfd file descriptor. */</span> <span class="hl kwb">void</span> <span class="hl kwc">FenceTest</span><span class="hl opt">::</span><span class="hl kwd">signalFence</span><span class="hl opt">()</span> <span class="hl opt">{</span> <span class="hl kwb">uint64_t</span> value <span class="hl opt">=</span> <span class="hl num">1</span><span class="hl opt">;</span> <span class="hl kwb">int</span> ret<span class="hl opt">;</span> ret <span class="hl opt">=</span> <span class="hl kwd">write</span><span class="hl opt">(</span>efd2_<span class="hl opt">, &</span>value<span class="hl opt">,</span> <span class="hl kwa">sizeof</span><span class="hl opt">(</span>value<span class="hl opt">));</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>ret <span class="hl opt">!=</span> <span class="hl kwa">sizeof</span><span class="hl opt">(</span>value<span class="hl opt">))</span> cerr <span class="hl opt"><<</span> <span class="hl str">"Failed to signal fence"</span> <span class="hl opt"><<</span> endl<span class="hl opt">;</span> setFence_ <span class="hl opt">=</span> <span class="hl kwa">false</span><span class="hl opt">;</span> dispatcher_<span class="hl opt">-></span><span class="hl kwd">processEvents</span><span class="hl opt">();</span> <span class="hl opt">}</span> <span class="hl kwb">int</span> <span class="hl kwc">FenceTest</span><span class="hl opt">::</span><span class="hl kwd">run</span><span class="hl opt">()</span> <span class="hl opt">{</span> <span class="hl kwa">for</span> <span class="hl opt">(</span><span class="hl kwb">const</span> <span class="hl kwc">auto</span> <span class="hl opt">&[</span>i<span class="hl opt">,</span> buffer<span class="hl opt">] :</span> <span class="hl kwc">utils</span><span class="hl opt">::</span><span class="hl kwd">enumerate</span><span class="hl opt">(</span>allocator_<span class="hl opt">-></span><span class="hl kwd">buffers</span><span class="hl opt">(</span>stream_<span class="hl opt">))) {</span> <span class="hl kwc">std</span><span class="hl opt">::</span>unique_ptr<span class="hl opt"><</span>Request<span class="hl opt">></span> request <span class="hl opt">=</span> camera_<span class="hl opt">-></span><span class="hl kwd">createRequest</span><span class="hl opt">(</span>i<span class="hl opt">);</span> <span class="hl kwa">if</span> <span class="hl opt">(!</span>request<span class="hl opt">) {</span> cerr <span class="hl opt"><<</span> <span class="hl str">"Failed to create request"</span> <span class="hl opt"><<</span> endl<span class="hl opt">;</span> <span class="hl kwa">return</span> TestFail<span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwb">int</span> ret<span class="hl opt">;</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>i <span class="hl opt">==</span> expiredRequestId_<span class="hl opt">) {</span> <span class="hl com">/* This request will have a fence, and it will expire. */</span> fence_ <span class="hl opt">=</span> <span class="hl kwc">std</span><span class="hl opt">::</span>make_unique<span class="hl opt"><</span>Fence<span class="hl opt">>(</span><span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwd">move</span><span class="hl opt">(</span>eventFd_<span class="hl opt">));</span> <span class="hl kwa">if</span> <span class="hl opt">(!</span>fence_<span class="hl opt">-></span><span class="hl kwd">isValid</span><span class="hl opt">()) {</span> cerr <span class="hl opt"><<</span> <span class="hl str">"Fence should be valid"</span> <span class="hl opt"><<</span> endl<span class="hl opt">;</span> <span class="hl kwa">return</span> TestFail<span class="hl opt">;</span> <span class="hl opt">}</span> ret <span class="hl opt">=</span> request<span class="hl opt">-></span><span class="hl kwd">addBuffer</span><span class="hl opt">(</span>stream_<span class="hl opt">,</span> buffer<span class="hl opt">.</span><span class="hl kwd">get</span><span class="hl opt">(),</span> <span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwd">move</span><span class="hl opt">(</span>fence_<span class="hl opt">));</span> <span class="hl opt">}</span> <span class="hl kwa">else</span> <span class="hl opt">{</span> <span class="hl com">/* All other requests will have no Fence. */</span> ret <span class="hl opt">=</span> request<span class="hl opt">-></span><span class="hl kwd">addBuffer</span><span class="hl opt">(</span>stream_<span class="hl opt">,</span> buffer<span class="hl opt">.</span><span class="hl kwd">get</span><span class="hl opt">());</span> <span class="hl opt">}</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>ret<span class="hl opt">) {</span> cerr <span class="hl opt"><<</span> <span class="hl str">"Failed to associate buffer with request"</span> <span class="hl opt"><<</span> endl<span class="hl opt">;</span> <span class="hl kwa">return</span> TestFail<span class="hl opt">;</span> <span class="hl opt">}</span> requests_<span class="hl opt">.</span><span class="hl kwd">push_back</span><span class="hl opt">(</span><span class="hl kwc">std</span><span class="hl opt">::</span><span class="hl kwd">move</span><span class="hl opt">(</span>request<span class="hl opt">));</span> <span class="hl opt">}</span> camera_<span class="hl opt">-></span>requestCompleted<span class="hl opt">.</span><span class="hl kwd">connect</span><span class="hl opt">(</span><span class="hl kwa">this</span><span class="hl opt">, &</span><span class="hl kwc">FenceTest</span><span class="hl opt">::</span>requestComplete<span class="hl opt">);</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>camera_<span class="hl opt">-></span><span class="hl kwd">start</span><span class="hl opt">()) {</span> cerr <span class="hl opt"><<</span> <span class="hl str">"Failed to start camera"</span> <span class="hl opt"><<</span> endl<span class="hl opt">;</span> <span class="hl kwa">return</span> TestFail<span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwa">for</span> <span class="hl opt">(</span><span class="hl kwc">std</span><span class="hl opt">::</span>unique_ptr<span class="hl opt"><</span>Request<span class="hl opt">> &</span>request <span class="hl opt">:</span> requests_<span class="hl opt">) {</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>camera_<span class="hl opt">-></span><span class="hl kwd">queueRequest</span><span class="hl opt">(</span>request<span class="hl opt">.</span><span class="hl kwd">get</span><span class="hl opt">())) {</span> cerr <span class="hl opt"><<</span> <span class="hl str">"Failed to queue request"</span> <span class="hl opt"><<</span> endl<span class="hl opt">;</span> <span class="hl kwa">return</span> TestFail<span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl opt">}</span> expectedCompletionResult_ <span class="hl opt">=</span> <span class="hl kwa">true</span><span class="hl opt">;</span> <span class="hl com">/* This timer serves to signal fences associated with "signalledRequestId_" */</span> Timer fenceTimer<span class="hl opt">;</span> fenceTimer<span class="hl opt">.</span>timeout<span class="hl opt">.</span><span class="hl kwd">connect</span><span class="hl opt">(</span><span class="hl kwa">this</span><span class="hl opt">, &</span><span class="hl kwc">FenceTest</span><span class="hl opt">::</span>signalFence<span class="hl opt">);</span> <span class="hl com">/* Loop for one second. */</span> Timer timer<span class="hl opt">;</span> timer<span class="hl opt">.</span><span class="hl kwd">start</span><span class="hl opt">(</span><span class="hl num">1000</span>ms<span class="hl opt">);</span> <span class="hl kwa">while</span> <span class="hl opt">(</span>timer<span class="hl opt">.</span><span class="hl kwd">isRunning</span><span class="hl opt">() &&</span> expectedCompletionResult_<span class="hl opt">) {</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>completedRequest_ <span class="hl opt">==</span> signalledRequestId_ <span class="hl opt">&&</span> setFence_<span class="hl opt">)</span> <span class="hl com">/*</span> <span class="hl com"> * signalledRequestId_ has just completed and it has</span> <span class="hl com"> * been re-queued with a fence. Start the timer to</span> <span class="hl com"> * signal the fence in 10 msec.</span> <span class="hl com"> */</span> fenceTimer<span class="hl opt">.</span><span class="hl kwd">start</span><span class="hl opt">(</span><span class="hl num">10</span>ms<span class="hl opt">);</span> dispatcher_<span class="hl opt">-></span><span class="hl kwd">processEvents</span><span class="hl opt">();</span> <span class="hl opt">}</span> camera_<span class="hl opt">-></span>requestCompleted<span class="hl opt">.</span><span class="hl kwd">disconnect</span><span class="hl opt">();</span> <span class="hl kwa">if</span> <span class="hl opt">(</span>camera_<span class="hl opt">-></span><span class="hl kwd">stop</span><span class="hl opt">()) {</span> cerr <span class="hl opt"><<</span> <span class="hl str">"Failed to stop camera"</span> <span class="hl opt"><<</span> endl<span class="hl opt">;</span> <span class="hl kwa">return</span> TestFail<span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwa">return</span> expectedCompletionResult_ <span class="hl opt">?</span> TestPass <span class="hl opt">:</span> TestFail<span class="hl opt">;</span> <span class="hl opt">}</span> <span class="hl kwd">TEST_REGISTER</span><span class="hl opt">(</span>FenceTest<span class="hl opt">)</span> </code></pre></td></tr></table> </div> <!-- class=content --> <div class='footer'>generated by <a href='https://git.zx2c4.com/cgit/about/'>cgit v1.2.1</a> (<a href='https://git-scm.com/'>git 2.18.0</a>) at 2025-03-18 00:50:37 +0000</div> </div> <!-- id=cgit --> </body> </html>