1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 2011-2016. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  */
20 
21 #include "erl_driver.h"
22 
23 #define NO_ASYNC_JOBS 10000
24 
25 static void stop(ErlDrvData drv_data);
26 static ErlDrvData start(ErlDrvPort port,
27 			char *command);
28 static void output(ErlDrvData drv_data,
29 		   char *buf, ErlDrvSizeT len);
30 static void ready_async(ErlDrvData drv_data,
31 			ErlDrvThreadData thread_data);
32 
33 static ErlDrvEntry async_blast_drv_entry = {
34     NULL /* init */,
35     start,
36     stop,
37     output,
38     NULL /* ready_input */,
39     NULL /* ready_output */,
40     "async_blast_drv",
41     NULL /* finish */,
42     NULL /* handle */,
43     NULL /* control */,
44     NULL /* timeout */,
45     NULL /* outputv */,
46     ready_async,
47     NULL /* flush */,
48     NULL /* call */,
49     NULL /* event */,
50     ERL_DRV_EXTENDED_MARKER,
51     ERL_DRV_EXTENDED_MAJOR_VERSION,
52     ERL_DRV_EXTENDED_MINOR_VERSION,
53     ERL_DRV_FLAG_USE_PORT_LOCKING,
54     NULL /* handle2 */,
55     NULL /* handle_monitor */
56 };
57 
58 typedef struct {
59     ErlDrvPort port;
60     ErlDrvTermData port_id;
61     ErlDrvTermData caller;
62     int counter;
63 } async_blast_data_t;
64 
65 
DRIVER_INIT(async_blast_drv)66 DRIVER_INIT(async_blast_drv)
67 {
68     return &async_blast_drv_entry;
69 }
70 
stop(ErlDrvData drv_data)71 static void stop(ErlDrvData drv_data)
72 {
73     driver_free((void *) drv_data);
74 }
75 
start(ErlDrvPort port,char * command)76 static ErlDrvData start(ErlDrvPort port,
77 			char *command)
78 {
79     async_blast_data_t *abd;
80 
81     abd = driver_alloc(sizeof(async_blast_data_t));
82     if (!abd)
83 	return ERL_DRV_ERROR_GENERAL;
84 
85     abd->port = port;
86     abd->port_id = driver_mk_port(port);
87     abd->counter = 0;
88     return (ErlDrvData) abd;
89 }
90 
async_invoke(void * data)91 static void async_invoke(void *data)
92 {
93 
94 }
95 #include <stdio.h>
96 
ready_async(ErlDrvData drv_data,ErlDrvThreadData thread_data)97 static void ready_async(ErlDrvData drv_data,
98 			ErlDrvThreadData thread_data)
99 {
100     async_blast_data_t *abd = (async_blast_data_t *) drv_data;
101     if (--abd->counter == 0) {
102 	ErlDrvTermData spec[] = {
103 	    ERL_DRV_PORT, abd->port_id,
104 	    ERL_DRV_ATOM, driver_mk_atom("done"),
105 	    ERL_DRV_TUPLE, 2
106 	};
107 	erl_drv_send_term(abd->port_id, abd->caller,
108 			  spec, sizeof(spec)/sizeof(spec[0]));
109     }
110 }
111 
output(ErlDrvData drv_data,char * buf,ErlDrvSizeT len)112 static void output(ErlDrvData drv_data,
113 		   char *buf, ErlDrvSizeT len)
114 {
115     async_blast_data_t *abd = (async_blast_data_t *) drv_data;
116     if (abd->counter == 0) {
117 	int i;
118 	abd->caller = driver_caller(abd->port);
119 	abd->counter = NO_ASYNC_JOBS;
120 	for (i = 0; i < NO_ASYNC_JOBS; i++) {
121 	    if (0 > driver_async(abd->port, NULL, async_invoke, NULL, NULL)) {
122 		driver_failure_atom(abd->port, "driver_async_failed");
123 		break;
124 	    }
125 	}
126     }
127 }
128