1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
|
<?xml version="1.0" encoding="latin1" ?>
<!DOCTYPE cref SYSTEM "cref.dtd">
<cref>
<header>
<copyright>
<year>2001</year><year>2010</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
The contents of this file are subject to the Erlang Public License,
Version 1.1, (the "License"); you may not use this file except in
compliance with the License. You should have received a copy of the
Erlang Public License along with this software. If not, it can be
retrieved online at http://www.erlang.org/.
Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
the License for the specific language governing rights and limitations
under the License.
</legalnotice>
<title>driver_entry</title>
<prepared>Jakob Cederlund</prepared>
<responsible>Jakob Cederlund</responsible>
<docno>1</docno>
<approved></approved>
<checked></checked>
<date>2001-10-01</date>
<rev>PA1</rev>
<file>driver_entry.xml</file>
</header>
<lib>driver_entry</lib>
<libsummary>The driver-entry structure used by erlang drivers.</libsummary>
<description>
<p>As of erts version 5.5.3 the driver interface has been extended
(see <seealso marker="driver_entry#extended_marker">extended marker</seealso>).
The extended interface introduces
<seealso marker="erl_driver#version_management">version management</seealso>,
the possibility to pass capability flags
(see <seealso marker="driver_entry#driver_flags">driver flags</seealso>)
to the runtime system at driver initialization, and some new
driver API functions. </p>
<note>
<p>Old drivers (compiled with an <c>erl_driver.h</c> from an
earlier erts version than 5.5.3) have to be recompiled
(but do not have to use the extended interface).</p>
</note>
<p>The <c>driver_entry</c> structure is a C struct that all erlang
drivers define. It contains entry points for the erlang driver
that are called by the erlang emulator when erlang code accesses
the driver.</p>
<p>
<marker id="emulator"></marker>
The <seealso marker="driver_entry">erl_driver</seealso> driver
API functions need a port handle
that identifies the driver instance (and the port in the
emulator). This is only passed to the <c>start</c> function, but
not to the other functions. The <c>start</c> function returns a
driver-defined handle that is passed to the other functions. A
common practice is to have the <c>start</c> function allocate
some application-defined structure and stash the <c>port</c>
handle in it, to use it later with the driver API functions.</p>
<p>The driver call-back functions are called synchronously from the
erlang emulator. If they take too long before completing, they
can cause timeouts in the emulator. Use the queue or
asynchronous calls if necessary, since the emulator must be
responsive.</p>
<p>The driver structure contains the name of the driver and some
15 function pointers. These pointers are called at different
times by the emulator.</p>
<p>The only exported function from the driver is
<c>driver_init</c>. This function returns the <c>driver_entry</c>
structure that points to the other functions in the driver. The
<c>driver_init</c> function is declared with a macro
<c>DRIVER_INIT(drivername)</c>. (This is because different OS's
have different names for it.)</p>
<p>When writing a driver in C++, the driver entry should be of
<c>"C"</c> linkage. One way to do this is to put this line
somewhere before the driver entry:
<c>extern "C" DRIVER_INIT(drivername);</c>.</p>
<p>When the driver has passed the <c>driver_entry</c> over to
the emulator, the driver is <em>not</em> allowed to modify the
<c>driver_entry</c>.</p>
<note>
<p>Do <em>not</em> declare the <c>driver_entry</c><c>const</c>. This since the emulator needs to
modify the <c>handle</c>, and the <c>handle2</c>
fields. A statically allocated, and <c>const</c>
declared <c>driver_entry</c> may be located in
read only memory which will cause the emulator
to crash.</p>
</note>
</description>
<section>
<title>DATA TYPES</title>
<taglist>
<tag><b>ErlDrvEntry</b></tag>
<item>
<p/>
<code type="none">
typedef struct erl_drv_entry {
int (*init)(void); /* called at system start up for statically
linked drivers, and after loading for
dynamically loaded drivers */
#ifndef ERL_SYS_DRV
ErlDrvData (*start)(ErlDrvPort port, char *command);
/* called when open_port/2 is invoked.
return value -1 means failure. */
#else
ErlDrvData (*start)(ErlDrvPort port, char *command, SysDriverOpts* opts);
/* special options, only for system driver */
#endif
void (*stop)(ErlDrvData drv_data);
/* called when port is closed, and when the
emulator is halted. */
void (*output)(ErlDrvData drv_data, char *buf, int len);
/* called when we have output from erlang to
the port */
void (*ready_input)(ErlDrvData drv_data, ErlDrvEvent event);
/* called when we have input from one of
the driver's handles) */
void (*ready_output)(ErlDrvData drv_data, ErlDrvEvent event);
/* called when output is possible to one of
the driver's handles */
char *driver_name; /* name supplied as command
in open_port XXX ? */
void (*finish)(void); /* called before unloading the driver -
DYNAMIC DRIVERS ONLY */
void *handle; /* Reserved -- Used by emulator internally */
int (*control)(ErlDrvData drv_data, unsigned int command, char *buf,
int len, char **rbuf, int rlen);
/* "ioctl" for drivers - invoked by
port_control/3) */
void (*timeout)(ErlDrvData drv_data); /* Handling of timeout in driver */
void (*outputv)(ErlDrvData drv_data, ErlIOVec *ev);
/* called when we have output from erlang
to the port */
void (*ready_async)(ErlDrvData drv_data, ErlDrvThreadData thread_data);
void (*flush)(ErlDrvData drv_data);
/* called when the port is about to be
closed, and there is data in the
driver queue that needs to be flushed
before 'stop' can be called */
int (*call)(ErlDrvData drv_data, unsigned int command, char *buf,
int len, char **rbuf, int rlen, unsigned int *flags);
/* Works mostly like 'control', a syncronous
call into the driver. */
void (*event)(ErlDrvData drv_data, ErlDrvEvent event,
ErlDrvEventData event_data);
/* Called when an event selected by
driver_event() has occurred */
int extended_marker; /* ERL_DRV_EXTENDED_MARKER */
int major_version; /* ERL_DRV_EXTENDED_MAJOR_VERSION */
int minor_version; /* ERL_DRV_EXTENDED_MINOR_VERSION */
int driver_flags; /* ERL_DRV_FLAGs */
void *handle2; /* Reserved -- Used by emulator internally */
void (*process_exit)(ErlDrvData drv_data, ErlDrvMonitor *monitor);
/* Called when a process monitor fires */
void (*stop_select)(ErlDrvEvent event, void* reserved);
/* Called to close an event object */
} ErlDrvEntry;
</code>
<p/>
<taglist>
<tag><marker id="init"/>int (*init)(void)</tag>
<item>
<p>This is called directly after the driver has been loaded by
<c>erl_ddll:load_driver/2</c>. (Actually when the driver is
added to the driver list.) The driver should return 0, or if
the driver can't initialize, -1.</p>
</item>
<tag><marker id="start"/>ErlDrvData (*start)(ErlDrvPort port, char* command)</tag>
<item>
<p>This is called when the driver is instantiated, when
<c>open_port/2</c> is called. The driver should return a
number >= 0 or a pointer, or if the driver can't be started,
one of three error codes should be returned:</p>
<p>ERL_DRV_ERROR_GENERAL - general error, no error code</p>
<p>ERL_DRV_ERROR_ERRNO - error with error code in erl_errno</p>
<p>ERL_DRV_ERROR_BADARG - error, badarg</p>
<p>If an error code is returned, the port isn't started.</p>
</item>
<tag><marker id="stop"/>void (*stop)(ErlDrvData drv_data)</tag>
<item>
<p>This is called when the port is closed, with
<c>port_close/1</c> or <c>Port ! {self(), close}</c>. Note
that terminating the port owner process also closes the
port. If <c>drv_data</c> is a pointer to memory allocated in
<c>start</c>, then <c>stop</c> is the place to deallocate that
memory.</p>
</item>
<tag><marker id="output"/>void (*output)(ErlDrvData drv_data, char *buf, int len)</tag>
<item>
<p>This is called when an erlang process has sent data to the
port. The data is pointed to by <c>buf</c>, and is
<c>len</c> bytes. Data is sent to the port with <c>Port ! {self(), {command, Data}}</c>, or with
<c>port_command/2</c>. Depending on how the port was opened,
it should be either a list of integers 0...255 or a
binary. See <c>open_port/3</c> and <c>port_command/2</c>.</p>
</item>
<tag><marker id="ready_input"/>void (*ready_input)(ErlDrvData drv_data, ErlDrvEvent event)</tag>
<tag><marker id="ready_output"/>void (*ready_output)(ErlDrvData drv_data, ErlDrvEvent event)</tag>
<item>
<p>This is called when a driver event (given in the
<c>event</c> parameter) is signaled. This is used to help
asynchronous drivers "wake up" when something happens.</p>
<p>On unix the <c>event</c> is a pipe or socket handle (or
something that the <c>select</c> system call understands).</p>
<p>On Windows the <c>event</c> is an Event or Semaphore (or
something that the <c>WaitForMultipleObjects</c> API
function understands). (Some trickery in the emulator allows
more than the built-in limit of 64 <c>Events</c> to be used.)</p>
<p>To use this with threads and asynchronous routines, create a
pipe on unix and an Event on Windows. When the routine
completes, write to the pipe (use <c>SetEvent</c> on
Windows), this will make the emulator call
<c>ready_input</c> or <c>ready_output</c>.</p>
</item>
<tag><marker id="driver_name"/>char *driver_name</tag>
<item>
<p>This is the name of the driver, it must correspond to the
atom used in <c>open_port</c>, and the name of the driver
library file (without the extension).</p>
</item>
<tag><marker id="finish"/>void (*finish)(void)</tag>
<item>
<p>This function is called by the <c>erl_ddll</c> driver when the
driver is unloaded. (It is only called in dynamic drivers.)</p>
<p>The driver is only unloaded as a result of calling
<c>unload_driver/1</c>, or when the emulator halts.</p>
</item>
<tag>void *handle</tag>
<item>
<p>This field is reserved for the emulator's internal use. The
emulator will modify this field; therefore, it is important
that the <c>driver_entry</c> isn't declared <c>const</c>.</p>
</item>
<tag><marker id="control"></marker>int (*control)(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen)</tag>
<item>
<p>This is a special routine invoked with the erlang function
<c>port_control/3</c>. It works a little like an "ioctl" for
erlang drivers. The data given to <c>port_control/3</c>
arrives in <c>buf</c> and <c>len</c>. The driver may send
data back, using <c>*rbuf</c> and <c>rlen</c>.</p>
<p>This is the fastest way of calling a driver and get a
response. It won't make any context switch in the erlang
emulator, and requires no message passing. It is suitable
for calling C function to get faster execution, when erlang
is too slow.</p>
<p>If the driver wants to return data, it should return it in
<c>rbuf</c>. When <c>control</c> is called,
<c>*rbuf</c> points to a default buffer of <c>rlen</c> bytes, which
can be used to return data. Data is returned different depending on
the port control flags (those that are set with
<seealso marker="erl_driver#set_port_control_flags">set_port_control_flags</seealso>).
</p>
<p>If the flag is set to <c>PORT_CONTROL_FLAG_BINARY</c>,
a binary will be returned. Small binaries can be returned by writing
the raw data into the default buffer. A binary can also be
returned by setting <c>*rbuf</c> to point to a binary allocated with
<seealso marker="erl_driver#driver_alloc_binary">driver_alloc_binary</seealso>.
This binary will be freed automatically after <c>control</c> has returned.
The driver can retain the binary for <em>read only</em> access with
<seealso marker="erl_driver#driver_binary_inc_refc">driver_binary_inc_refc</seealso> to be freed later with
<seealso marker="erl_driver#driver_free_binary">driver_free_binary</seealso>.
It is never allowed to alter the binary after <c>control</c> has returned.
If <c>*rbuf</c> is set to NULL, an empty list will be returned.
</p>
<p>If the flag is set to <c>0</c>, data is returned as a
list of integers. Either use the default buffer or set
<c>*rbuf</c> to point to a larger buffer allocated with
<seealso marker="erl_driver#driver_alloc">driver_alloc</seealso>.
The buffer will be freed automatically after <c>control</c> has returned.</p>
<p>Using binaries is faster if more than a few bytes are returned.</p>
<p>The return value is the number of bytes returned in
<c>*rbuf</c>.</p>
</item>
<tag><marker id="timeout"/>void (*timeout)(ErlDrvData drv_data)</tag>
<item>
<p>This function is called any time after the driver's timer
reaches 0. The timer is activated with
<c>driver_set_timer</c>. There are no priorities or ordering
among drivers, so if several drivers time out at the same
time, any one of them is called first.</p>
</item>
<tag><marker id="outputv"/>void (*outputv)(ErlDrvData drv_data, ErlIOVec *ev)</tag>
<item>
<p>This function is called whenever the port is written to. If
it is <c>NULL</c>, the <c>output</c> function is called
instead. This function is faster than <c>output</c>, because
it takes an <c>ErlIOVec</c> directly, which requires no
copying of the data. The port should be in binary mode, see
<c>open_port/2</c>.</p>
<p>The <c>ErlIOVec</c> contains both a <c>SysIOVec</c>,
suitable for <c>writev</c>, and one or more binaries. If
these binaries should be retained, when the driver returns
from <c>outputv</c>, they can be queued (using <seealso marker="erl_driver#driver_enq_bin">driver_enq_bin</seealso>
for instance), or if they are kept in a static or global
variable, the reference counter can be incremented.</p>
</item>
<tag><marker id="ready_async"/>void (*ready_async)(ErlDrvData drv_data, ErlDrvThreadData thread_data)</tag>
<item>
<p>This function is called after an asynchronous call has
completed. The asynchronous call is started with <seealso marker="erl_driver#driver_async">driver_async</seealso>.
This function is called from the erlang emulator thread, as
opposed to the asynchronous function, which is called in
some thread (if multithreading is enabled).</p>
</item>
<tag><marker id="call"/>int (*call)(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen, unsigned int *flags)</tag>
<item>
<p>This function is called from <c>erlang:port_call/3</c>. It
works a lot like the <c>control</c> call-back, but uses the
external term format for input and output.</p>
<p><c>command</c> is an integer, obtained from the call from
erlang (the second argument to <c>erlang:port_call/3</c>).</p>
<p><c>buf</c> and <c>len</c> provide the arguments to the call
(the third argument to <c>erlang:port_call/3</c>). They can
be decoded using <c>ei</c> functions.</p>
<p><c>rbuf</c> points to a return buffer, <c>rlen</c> bytes
long. The return data should be a valid erlang term in the
external (binary) format. This is converted to an erlang
term and returned by <c>erlang:port_call/3</c> to the
caller. If more space than <c>rlen</c> bytes is needed to
return data, <c>*rbuf</c> can be set to memory allocated with
<c>driver_alloc</c>. This memory will be freed automatically
after <c>call</c> has returned.</p>
<p>The return value is the number of bytes returned in
<c>*rbuf</c>. If <c>ERL_DRV_ERROR_GENERAL</c> is returned
(or in fact, anything < 0), <c>erlang:port_call/3</c> will
throw a <c>BAD_ARG</c>.</p>
</item>
<tag>void (*event)(ErlDrvData drv_data, ErlDrvEvent event, ErlDrvEventData event_data)</tag>
<item>
<p>Intentionally left undocumented.</p>
</item>
<tag><marker id="extended_marker"/>int extended_marker</tag>
<item>
<p>
This field should either be equal to <c>ERL_DRV_EXTENDED_MARKER</c>
or <c>0</c>. An old driver (not aware of the extended driver
interface) should set this field to <c>0</c>. If this field is
equal to <c>0</c>, all the fields following this field also
<em>have</em> to be <c>0</c>, or <c>NULL</c> in case it is a
pointer field.
</p>
</item>
<tag>int major_version</tag>
<item>
<p>This field should equal <c>ERL_DRV_EXTENDED_MAJOR_VERSION</c> if
the <c>extended_marker</c> field equals
<c>ERL_DRV_EXTENDED_MARKER</c>.</p>
</item>
<tag>int minor_version</tag>
<item>
<p>
This field should equal <c>ERL_DRV_EXTENDED_MINOR_VERSION</c> if
the <c>extended_marker</c> field equals
<c>ERL_DRV_EXTENDED_MARKER</c>.
</p>
</item>
<tag><marker id="driver_flags"/>int driver_flags</tag>
<item>
<p>This field is used to pass driver capability information to the
runtime system. If the <c>extended_marker</c> field equals
<c>ERL_DRV_EXTENDED_MARKER</c>, it should contain <c>0</c> or
driver flags (<c>ERL_DRV_FLAG_*</c>) ored bitwise. Currently
the following driver flags exist:
</p>
<taglist>
<tag><c>ERL_DRV_FLAG_USE_PORT_LOCKING</c></tag>
<item>
The runtime system will use port level locking on
all ports executing this driver instead of driver
level locking when the driver is run in a runtime
system with SMP support. For more information see the
<seealso marker="erl_driver#smp_support">erl_driver</seealso>
documentation.
</item>
<tag><c>ERL_DRV_FLAG_SOFT_BUSY</c></tag>
<item>
Marks that driver instances can handle being called
in the <seealso marker="#output">output</seealso> and/or
<seealso marker="#outputv">outputv</seealso> callbacks even
though a driver instance has marked itself as busy (see
<seealso marker="erl_driver#set_busy_port">set_busy_port()</seealso>).
Since erts version 5.7.4 this flag is required for drivers used
by the Erlang distribution (the behaviour has always been
required by drivers used by the distribution).
</item>
</taglist>
</item>
<tag>void *handle2</tag>
<item>
<p>
This field is reserved for the emulator's internal use. The
emulator will modify this field; therefore, it is important
that the <c>driver_entry</c> isn't declared <c>const</c>.
</p>
</item>
<tag><marker id="process_exit"/>void (*process_exit)(ErlDrvData drv_data, ErlDrvMonitor *monitor)</tag>
<item>
<p>This callback is called when a monitored process exits. The
<c>drv_data</c> is the data associated with the port for which
the process is monitored (using <seealso marker="erl_driver#driver_monitor_process">driver_monitor_process</seealso>)
and the <c>monitor</c> corresponds to the <c>ErlDrvMonitor</c>
structure filled
in when creating the monitor. The driver interface function
<seealso marker="erl_driver#driver_get_monitored_process">driver_get_monitored_process</seealso>
can be used to retrieve the process id of the exiting process as
an <c>ErlDrvTermData</c>.</p>
</item>
<tag><marker id="stop_select"/>void (*stop_select)(ErlDrvEvent event, void* reserved)</tag>
<item>
<p>This function is called on behalf of
<seealso marker="erl_driver#driver_select">driver_select</seealso>
when it is safe to close an event object.</p>
<p>A typical implementation on Unix is to do
<c>close((int)event)</c>.</p>
<p>Argument <c>reserved</c> is intended for future use and should be ignored.</p>
<p>In contrast to most of the other call-back functions,
<c>stop_select</c> is called independent of any port. No
<c>ErlDrvData</c> argument is passed to the function. No
driver lock or port lock is guaranteed to be held. The port that
called <c>driver_select</c> might even be closed at the
time <c>stop_select</c> is called. But it could also be
the case that <c>stop_select</c> is called directly by
<c>driver_select</c>.</p>
<p>It is not allowed to call any functions in the
<seealso marker="erl_driver">driver API</seealso> from
<c>stop_select</c>. This strict limitation is due to the
volatile context that <c>stop_select</c> may be called.</p>
</item>
</taglist>
</item>
</taglist>
</section>
<section>
<title>SEE ALSO</title>
<p><seealso marker="erl_driver">erl_driver(3)</seealso>,
<seealso marker="kernel:erl_ddll">erl_ddll(3)</seealso>,
<seealso marker="erts:erlang">erlang(3)</seealso>,
kernel(3)</p>
</section>
</cref>
|