262
265
could, under rare circumstances, mean that drivers have to
263
266
be slightly modified. If so, this will of course be documented.
264
267
<c>ERL_DRV_EXTENDED_MINOR_VERSION</c> will be incremented when
265
new features are added. The runtime system use the minor version
268
new features are added. The runtime system uses the minor version
266
269
of the driver to determine what features to use.
267
270
The runtime system will refuse to load a driver if the major
268
271
versions differ, or if the major versions are equal and the
269
272
minor version used by the driver is greater than the one used
270
273
by the runtime system.</p>
271
<p>The emulator tries to check that a driver that doesn't use the
272
extended driver interface isn't incompatible when loading it.
273
It can, however, not make sure that it isn't incompatible. Therefore,
274
when loading a driver that doesn't use the extended driver
275
interface, there is a risk that it will be loaded also when
276
the driver is incompatible. When the driver use the extended driver
277
interface, the emulator can verify that it isn't of an incompatible
278
driver version. You are therefore advised to use the extended driver
274
<p>The emulator will refuse to load a driver that does not use
275
the extended driver interface since,
276
to allow for 64-bit capable drivers,
277
incompatible type changes for the callbacks
278
<seealso marker="driver_entry#output">output</seealso>,
279
<seealso marker="driver_entry#control">control</seealso> and
280
<seealso marker="driver_entry#call">call</seealso>
281
were introduced in release R15B. A driver written
282
with the old types would compile with warnings and when
283
called return garbage sizes to the emulator causing it
284
to read random memory and create huge incorrect result blobs.</p>
285
<p>Therefore it is not enough to just recompile drivers written with
286
version management for pre-R15B types; the types has to be changed
287
in the driver suggesting other rewrites especially regarding
288
size variables. Investigate all warnings when recompiling!</p>
289
<p>Also, the API driver functions <c>driver_output*</c>,
290
<c>driver_vec_to_buf</c>, <c>driver_alloc/realloc*</c>
291
and the <c>driver_*</c> queue functions were changed to have
292
larger length arguments and return values. This is a
293
lesser problem since code that passes smaller types
294
will get them auto converted in the calls and as long as
295
the driver does not handle sizes that overflow an <c>int</c>
296
all will work as before.</p>
302
<marker id="rewrites_for_64_bits"/>
304
REWRITES FOR 64-BIT DRIVER INTERFACE
307
For erts-5.9 two new integer types
308
<seealso marker="#ErlDrvSizeT">ErlDrvSizeT</seealso> and
309
<seealso marker="#ErlDrvSSizeT">ErlDrvSSizeT</seealso>
310
were introduced that can hold 64-bit sizes if necessary.
313
To not update a driver and just recompile it probably works
314
when building for a 32-bit machine creating a false sense of security.
315
Hopefully that will generate many important warnings.
316
But when recompiling the same driver later on for a 64-bit machine
317
there <em>will</em> be warnings and almost certainly crashes.
318
So it is a BAD idea to postpone updating the driver and
319
not fixing the warnings!
322
When recompiling with <c>gcc</c> use the <c>-Wstrict-prototypes</c>
323
flag to get better warnings. Try to find a similar flag if you
324
are using some other compiler.
327
Here follows a checklist for rewriting a pre erts-5.9 driver,
328
most important first.
331
<tag>Return types for driver callbacks</tag>
334
Rewrite driver callback
335
<c><seealso marker="driver_entry#control">control</seealso></c>
336
to use return type <c>ErlDrvSSizeT</c> instead of <c>int</c>.
339
Rewrite driver callback
340
<c><seealso marker="driver_entry#call">call</seealso></c>
341
to use return type <c>ErlDrvSSizeT</c> instead of <c>int</c>.
345
These changes are essential to not crash the emulator
346
or worse cause malfunction.
347
Without them a driver may return garbage in the high 32 bits
348
to the emulator causing it to build a huge result from random
349
bytes either crashing on memory allocation or succeeding with
350
a random result from the driver call.
354
<tag>Arguments to driver callbacks</tag>
358
<c><seealso marker="driver_entry#output">output</seealso></c>
359
now gets <c>ErlDrvSizeT</c> as 3:rd argument instead
360
of previously <c>int</c>.
364
<c><seealso marker="driver_entry#control">control</seealso></c>
365
now gets <c>ErlDrvSizeT</c> as 4:th and 6:th arguments instead
366
of previously <c>int</c>.
370
<c><seealso marker="driver_entry#call">call</seealso></c>
371
now gets <c>ErlDrvSizeT</c> as 4:th and 6:th arguments instead
372
of previously <c>int</c>.
375
Sane compiler's calling conventions probably make these changes
376
necessary only for a driver to handle data chunks that require
377
64-bit size fields (mostly larger than 2 GB since that is what
378
an <c>int</c> of 32 bits can hold). But it is possible to think
379
of non-sane calling conventions that would make the driver
380
callbacks mix up the arguments causing malfunction.
384
The argument type change is from signed to unsigned which
385
may cause problems for e.g. loop termination conditions or
386
error conditions if you just change the types all over the place.
390
<tag>Larger <c>size</c> field in <c>ErlIOVec</c></tag>
393
The <c>size</c> field in
394
<seealso marker="#ErlIOVec"><c>ErlIOVec</c></seealso>
395
has been changed to <c>ErlDrvSizeT</c> from <c>int</c>.
396
Check all code that use that field.
399
Automatic type casting probably makes these changes necessary only
400
for a driver that encounters sizes larger than 32 bits.
404
The <c>size</c> field changed from signed to unsigned which
405
may cause problems for e.g. loop termination conditions or
406
error conditions if you just change the types all over the place.
410
<tag>Arguments and return values in the driver API</tag>
413
Many driver API functions has changed argument type
414
and/or return value to <c>ErlDrvSizeT</c> from mostly <c>int</c>.
415
Automatic type casting probably makes these changes necessary only
416
for a driver that encounters sizes larger than 32 bits.
419
<tag><seealso marker="#driver_output">driver_output</seealso></tag>
420
<item>3:rd argument</item>
421
<tag><seealso marker="#driver_output2">driver_output2</seealso></tag>
422
<item>3:rd and 5:th arguments</item>
424
<seealso marker="#driver_output_binary">driver_output_binary</seealso>
426
<item>3:rd 5:th and 6:th arguments</item>
427
<tag><seealso marker="#driver_outputv">driver_outputv</seealso></tag>
428
<item>3:rd and 5:th arguments</item>
430
<seealso marker="#driver_vec_to_buf">driver_vec_to_buf</seealso>
432
<item>3:rd argument and return value</item>
433
<tag><seealso marker="#driver_alloc">driver_alloc</seealso></tag>
434
<item>1:st argument</item>
435
<tag><seealso marker="#driver_realloc">driver_realloc</seealso></tag>
436
<item>2:nd argument</item>
438
<seealso marker="#driver_alloc_binary">driver_alloc_binary</seealso>
440
<item>1:st argument</item>
442
<seealso marker="#driver_realloc_binary">driver_realloc_binary</seealso>
444
<item>2:nd argument</item>
445
<tag><seealso marker="#driver_enq">driver_enq</seealso></tag>
446
<item>3:rd argument</item>
447
<tag><seealso marker="#driver_pushq">driver_pushq</seealso></tag>
448
<item>3:rd argument</item>
449
<tag><seealso marker="#driver_deq">driver_deq</seealso></tag>
450
<item>2:nd argument and return value</item>
451
<tag><seealso marker="#driver_sizeq">driver_sizeq</seealso></tag>
452
<item>return value</item>
453
<tag><seealso marker="#driver_enq_bin">driver_enq_bin</seealso></tag>
454
<item>3:rd and 4:th argument</item>
455
<tag><seealso marker="#driver_pushq_bin">driver_pushq_bin</seealso></tag>
456
<item>3:rd and 4:th argument</item>
457
<tag><seealso marker="#driver_enqv">driver_enqv</seealso></tag>
458
<item>3:rd argument</item>
459
<tag><seealso marker="#driver_pushqv">driver_pushqv</seealso></tag>
460
<item>3:rd argument</item>
461
<tag><seealso marker="#driver_peekqv">driver_peekqv</seealso></tag>
462
<item>return value</item>
466
This is a change from signed to unsigned which
467
may cause problems for e.g. loop termination conditions and
468
error conditions if you just change the types all over the place.
1258
<name><ret>ErlDrvSizeT</ret><nametext>driver_peekqv(ErlDrvPort port, ErlIOVec *ev)</nametext></name>
1259
<fsummary>Get the driver queue as an IO vector</fsummary>
1261
<marker id="driver_peekqv"></marker>
1263
This function retrieves the driver queue into a supplied
1264
<c>ErlIOVec</c> <c>ev</c>. It also returns the queue size.
1265
This is one of two ways to get data out of the queue.
1268
If <c>ev</c> is <c>NULL</c> all ones i.e. <c>-1</c> type cast to
1269
<c>ErlDrvSizeT</c> is returned.
1271
<p>Nothing is removed from the queue by this function, that must be done
1272
with <c>driver_deq</c>.</p>
1273
<p>This function can be called from an arbitrary thread if a
1274
<seealso marker="#ErlDrvPDL">port data lock</seealso>
1275
associated with the <c>port</c> is locked by the calling
1276
thread during the call.</p>
1071
1280
<name><ret>SysIOVec*</ret><nametext>driver_peekq(ErlDrvPort port, int *vlen)</nametext></name>
1072
1281
<fsummary>Get the driver queue as a vector</fsummary>
1074
1283
<marker id="driver_peekq"></marker>
1075
1284
<p>This function retrieves the driver queue as a pointer to an
1076
1285
array of <c>SysIOVec</c>s. It also returns the number of
1077
elements in <c>vlen</c>. This is the only way to get data
1286
elements in <c>vlen</c>. This is one of two ways to get data
1078
1287
out of the queue.</p>
1079
<p>Nothing is remove from the queue by this function, that must be done
1288
<p>Nothing is removed from the queue by this function, that must be done
1080
1289
with <c>driver_deq</c>.</p>
1081
1290
<p>The returned array is suitable to use with the Unix system
1082
1291
call <c>writev</c>.</p>