1 #include <stdio.h>
2 #include "erl_driver.h"
3 #include <errno.h>
4
5
6
7 /* -------------------------------------------------------------------------
8 ** Data types
9 **/
10
11 enum e_heavy {
12 heavy_off, heavy_set, heavy_reset
13 };
14
15 typedef struct _erl_drv_data {
16 ErlDrvPort erlang_port;
17 enum e_heavy heavy;
18 int crash;
19 } EchoDrvData;
20
21 static EchoDrvData echo_drv_data, *echo_drv_data_p;
22
23
24
25 /* -------------------------------------------------------------------------
26 ** Entry struct
27 **/
28
29 static EchoDrvData *echo_drv_start(ErlDrvPort port, char *command);
30 static void echo_drv_stop(ErlDrvData drv_data);
31 static void echo_drv_output(ErlDrvData drv_data, char *buf,
32 ErlDrvSizeT len);
33 static void echo_drv_finish(void);
34 static ErlDrvSSizeT echo_drv_control(ErlDrvData drv_data,
35 unsigned int command,
36 char *buf, ErlDrvSizeT len,
37 char **rbuf, ErlDrvSizeT rlen);
38
39 static ErlDrvEntry echo_drv_entry = {
40 NULL, /* init */
41 echo_drv_start,
42 echo_drv_stop,
43 echo_drv_output,
44 NULL, /* ready_input */
45 NULL, /* ready_output */
46 "echo_drv",
47 echo_drv_finish,
48 NULL, /* handle */
49 echo_drv_control,
50 NULL, /* timeout */
51 NULL, /* outputv */
52 NULL, /* ready_async */
53 NULL,
54 NULL,
55 NULL,
56 ERL_DRV_EXTENDED_MARKER,
57 ERL_DRV_EXTENDED_MAJOR_VERSION,
58 ERL_DRV_EXTENDED_MINOR_VERSION,
59 0,
60 NULL,
61 NULL,
62 NULL
63 };
64
65 /* -------------------------------------------------------------------------
66 ** Entry functions
67 **/
68
DRIVER_INIT(echo_drv)69 DRIVER_INIT(echo_drv)
70 {
71 echo_drv_data_p = NULL;
72 return &echo_drv_entry;
73 }
74
echo_drv_start(ErlDrvPort port,char * command)75 static EchoDrvData *echo_drv_start(ErlDrvPort port, char *command)
76 {
77 if (echo_drv_data_p != NULL) {
78 return ERL_DRV_ERROR_GENERAL;
79 }
80 echo_drv_data_p = &echo_drv_data;
81 echo_drv_data_p->erlang_port = port;
82 echo_drv_data_p->heavy = heavy_off;
83 echo_drv_data_p->crash = 0;
84 return echo_drv_data_p;
85 }
86
echo_drv_stop(EchoDrvData * data_p)87 static void echo_drv_stop(EchoDrvData *data_p) {
88 echo_drv_data_p = NULL;
89 }
90
echo_drv_output(ErlDrvData drv_data,char * buf,ErlDrvSizeT len)91 static void echo_drv_output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) {
92 EchoDrvData* data_p = (EchoDrvData *) drv_data;
93
94 if (data_p->crash) {
95 driver_failure_posix(data_p->erlang_port, EINTR);
96 return;
97 }
98
99 driver_output(data_p->erlang_port, buf, len);
100 switch (data_p->heavy) {
101 case heavy_off:
102 break;
103 case heavy_set:
104 set_port_control_flags(data_p->erlang_port, PORT_CONTROL_FLAG_HEAVY);
105 data_p->heavy = heavy_reset;
106 break;
107 case heavy_reset:
108 set_port_control_flags(data_p->erlang_port, 0);
109 data_p->heavy = heavy_off;
110 break;
111 }
112
113 }
114
echo_drv_finish()115 static void echo_drv_finish() {
116 echo_drv_data_p = NULL;
117 }
118
echo_drv_control(ErlDrvData drv_data,unsigned int command,char * buf,ErlDrvSizeT len,char ** rbuf,ErlDrvSizeT rlen)119 static ErlDrvSSizeT echo_drv_control(ErlDrvData drv_data,
120 unsigned int command,
121 char *buf, ErlDrvSizeT len,
122 char **rbuf, ErlDrvSizeT rlen) {
123 EchoDrvData* data_p = (EchoDrvData *) drv_data;
124 switch (command) {
125 case 'h':
126 data_p->heavy = heavy_set;
127 break;
128 case 'c':
129 data_p->crash = 1;
130 }
131 return 0;
132 }
133