64
64
const ErlDrvTermData driver_term_nil = (ErlDrvTermData)NIL;
66
static DE_List vanilla_de_list;
67
static DE_List spawn_de_list;
68
static DE_List fd_de_list;
66
erts_driver_t vanilla_driver;
67
erts_driver_t spawn_driver;
68
erts_driver_t fd_driver;
70
static int init_driver(erts_driver_t *, ErlDrvEntry *, DE_Handle *);
70
71
static void terminate_port(Port *p);
71
72
static void pdl_init(void);
72
static void init_de_list(DE_List *, ErlDrvEntry *, DE_Handle *);
74
74
static ERTS_INLINE ErlIOQueue*
75
75
drvport2ioq(ErlDrvPort drvport)
89
89
static ERTS_INLINE int
90
is_port_ioq_empty(Port *pp)
93
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));
94
if (!pp->port_data_lock)
95
res = pp->ioq.size == 0;
97
ErlDrvPDL pdl = pp->port_data_lock;
98
erts_mtx_lock(&pdl->mtx);
99
res = pp->ioq.size == 0;
100
erts_mtx_unlock(&pdl->mtx);
90
106
erts_is_port_ioq_empty(Port *pp)
93
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));
94
if (!pp->port_data_lock)
95
res = pp->ioq.size == 0;
97
ErlDrvPDL pdl = pp->port_data_lock;
98
erts_mtx_lock(&pdl->mtx);
99
res = pp->ioq.size == 0;
100
erts_mtx_unlock(&pdl->mtx);
108
return is_port_ioq_empty(pp);
1331
1345
erts_smp_tsd_set(driver_list_lock_status_key, (void *) 1);
1332
1346
erts_smp_mtx_lock(&erts_driver_list_lock);
1334
init_de_list(&fd_de_list, &fd_driver_entry, NULL);
1335
if (fd_driver_entry.init != NULL)
1336
(*fd_driver_entry.init)();
1337
init_de_list(&vanilla_de_list, &vanilla_driver_entry, NULL);
1338
if (vanilla_driver_entry.init != NULL)
1339
(*vanilla_driver_entry.init)();
1340
init_de_list(&spawn_de_list, &spawn_driver_entry, NULL);
1341
if (spawn_driver_entry.init != NULL)
1342
(*spawn_driver_entry.init)();
1348
init_driver(&fd_driver, &fd_driver_entry, NULL);
1349
init_driver(&vanilla_driver, &vanilla_driver_entry, NULL);
1350
init_driver(&spawn_driver, &spawn_driver_entry, NULL);
1343
1351
for (dp = driver_tab; *dp != NULL; dp++) {
1345
erts_add_driver_entry(*dp, 1); /* will call init as well! */
1353
erts_add_driver_entry(*dp, NULL, 1);
1348
1356
erts_smp_tsd_set(driver_list_lock_status_key, NULL);
2331
2351
if (p->reg != NULL)
2332
2352
erts_print(to, arg, "Registered as: %T\n", p->reg->name);
2334
if (p->drv_ptr == &fd_driver_entry) {
2354
if (p->drv_ptr == &fd_driver) {
2335
2355
erts_print(to, arg, "Port is UNIX fd not opened by emulator: %s\n", p->name);
2336
} else if (p->drv_ptr == &vanilla_driver_entry) {
2356
} else if (p->drv_ptr == &vanilla_driver) {
2337
2357
erts_print(to, arg, "Port is a file: %s\n",p->name);
2338
} else if (p->drv_ptr == &spawn_driver_entry) {
2358
} else if (p->drv_ptr == &spawn_driver) {
2339
2359
erts_print(to, arg, "Port controls external process: %s\n",p->name);
2341
2361
erts_print(to, arg, "Port controls linked-in driver: %s\n",p->name);
2427
2447
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p));
2429
2449
p->caller = NIL;
2430
if (p->drv_ptr->output != NULL) {
2431
(*p->drv_ptr->output)((ErlDrvData)p->drv_data, (char*)buf, len);
2435
static void missing_drv_callback(Port *p, ErlDrvEvent hndl, int mode);
2438
erts_port_ready_input(Port *p, ErlDrvEvent hndl)
2440
ERTS_SMP_CHK_NO_PROC_LOCKS;
2441
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p));
2443
ASSERT((p->status & ERTS_PORT_SFLGS_DEAD) == 0);
2445
if (!p->drv_ptr->ready_input)
2446
missing_drv_callback(p, hndl, DO_READ);
2448
(*p->drv_ptr->ready_input)((ErlDrvData) p->drv_data, hndl);
2449
/* NOTE some windows drivers use ->ready_input for input and output */
2450
if ((p->status & ERTS_PORT_SFLG_CLOSING) && erts_is_port_ioq_empty(p)) {
2457
erts_port_ready_output(Port *p, ErlDrvEvent hndl)
2459
ERTS_SMP_CHK_NO_PROC_LOCKS;
2460
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p));
2462
ASSERT((p->status & ERTS_PORT_SFLGS_DEAD) == 0);
2464
if (!p->drv_ptr->ready_output)
2465
missing_drv_callback(p, hndl, DO_WRITE);
2467
(*p->drv_ptr->ready_output)((ErlDrvData) p->drv_data, hndl);
2468
if ((p->status & ERTS_PORT_SFLG_CLOSING) && erts_is_port_ioq_empty(p)) {
2451
(*p->drv_ptr->output)((ErlDrvData)p->drv_data, (char*)buf, len);
2474
2455
int async_ready(Port *p, void* data)
2489
2470
ASSERT(!p->xports);
2492
if ((p->status & ERTS_PORT_SFLG_CLOSING) && erts_is_port_ioq_empty(p)) {
2473
if ((p->status & ERTS_PORT_SFLG_CLOSING) && is_port_ioq_empty(p)) {
2493
2474
terminate_port(p);
2496
2477
return need_free;
2500
erts_port_ready_event(Port* p, ErlDrvEvent hndl, ErlDrvEventData event_data)
2502
ERTS_SMP_CHK_NO_PROC_LOCKS;
2503
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p));
2504
ASSERT((p->status & ERTS_PORT_SFLGS_DEAD) == 0);
2506
if (!p->drv_ptr->event) {
2507
missing_drv_callback(p, hndl, 0);
2509
(*p->drv_ptr->event)((ErlDrvData)p->drv_data, hndl, event_data);
2510
if ((p->status & ERTS_PORT_SFLG_CLOSING) && erts_is_port_ioq_empty(p)) {
2517
missing_drv_callback(Port *p, ErlDrvEvent hndl, int mode)
2481
report_missing_drv_callback(Port *p, char *drv_type, char *callback)
2519
2483
ErtsPortNames *pnp = erts_get_port_names(p->id);
2522
erts_dsprintf_buf_t *dsbufp;
2525
case DO_READ|DO_WRITE:
2526
type = "Input/Output";
2527
callback = "->ready_input()/->ready_output()";
2531
callback = "->ready_output()";
2535
callback = "->ready_input()";
2537
driver_select((ErlDrvPort) internal_port_index(p->id), hndl, mode, 0);
2542
driver_event((ErlDrvPort) internal_port_index(p->id), hndl, NULL);
2546
dsbufp = erts_create_logger_dsbuf();
2547
erts_dsprintf(dsbufp,
2548
"%T: %s driver %s %s%s%s does not implement %s!\n",
2551
pnp->driver_name ? pnp->driver_name : "<unknown>",
2552
pnp->name ? "(" : "",
2553
pnp->name ? p->name : "",
2554
pnp->name ? ") " : "",
2484
char *unknown = "<unknown>";
2485
char *drv_name = pnp->driver_name ? pnp->driver_name : unknown;
2486
char *prt_name = pnp->name ? pnp->name : unknown;
2487
erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
2488
erts_dsprintf(dsbufp, "%T: %s driver '%s' ", p->id, drv_type, drv_name);
2489
if (sys_strcmp(drv_name, prt_name) != 0)
2490
erts_dsprintf(dsbufp, "(%s) ", prt_name);
2491
erts_dsprintf(dsbufp, "does not implement the %s callback!\n", callback);
2556
2492
erts_free_port_names(pnp);
2557
2493
erts_send_error_to_logger_nogl(dsbufp);
2562
2497
erts_stale_drv_select(Eterm port,
2563
2498
ErlDrvEvent hndl,
4540
init_de_list(DE_List *de_list, ErlDrvEntry *drv, DE_Handle *de_hndl)
4542
de_list->next = NULL;
4543
de_list->prev = NULL;
4546
drv->handle2 = (void *) de_list;
4547
de_list->de_hndl = de_hndl;
4550
if (drv->extended_marker == ERL_DRV_EXTENDED_MARKER
4551
&& drv->driver_flags & ERL_DRV_FLAG_USE_PORT_LOCKING) {
4552
de_list->driver_lock = NULL;
4555
de_list->driver_lock = erts_alloc(ERTS_ALC_T_DRIVER_LOCK,
4556
sizeof(erts_smp_mtx_t));
4557
erts_smp_mtx_init_x(de_list->driver_lock,
4559
#ifdef ERTS_ENABLE_LOCK_CHECK
4560
am_atom_put(drv->driver_name,
4561
sys_strlen(drv->driver_name))
4572
4458
#define ERL_DRV_SYS_INFO_SIZE(LAST_FIELD) \
4573
4459
(((size_t) &((ErlDrvSysInfo *) 0)->LAST_FIELD) \
4623
4509
if (si_size >= ERL_DRV_SYS_INFO_SIZE(scheduler_threads)) {
4624
4510
sip->async_threads = erts_async_max_threads;
4625
sip->scheduler_threads = erts_no_of_schedulers;
4511
sip->scheduler_threads = erts_no_schedulers;
4517
static ERTS_INLINE Port *
4518
get_current_port(void)
4520
ErtsSchedulerData *esdp = erts_get_scheduler_data();
4522
ASSERT(esdp->current_port);
4523
return esdp->current_port;
4527
* Default callbacks used if not supplied by driver.
4531
no_output_callback(ErlDrvData drv_data, char *buf, int len)
4537
no_event_callback(ErlDrvData drv_data, ErlDrvEvent event, ErlDrvEventData event_data)
4539
Port *prt = get_current_port();
4540
report_missing_drv_callback(prt, "Event", "event()");
4541
driver_event((ErlDrvPort) internal_port_index(prt->id), event, NULL);
4545
no_ready_input_callback(ErlDrvData drv_data, ErlDrvEvent event)
4547
Port *prt = get_current_port();
4548
report_missing_drv_callback(prt, "Input", "ready_input()");
4549
driver_select((ErlDrvPort) internal_port_index(prt->id), event, DO_READ, 0);
4553
no_ready_output_callback(ErlDrvData drv_data, ErlDrvEvent event)
4555
Port *prt = get_current_port();
4556
report_missing_drv_callback(prt, "Output", "ready_output()");
4557
driver_select((ErlDrvPort) internal_port_index(prt->id), event, DO_WRITE, 0);
4561
no_timeout_callback(ErlDrvData drv_data)
4567
init_driver(erts_driver_t *drv, ErlDrvEntry *de, DE_Handle *handle)
4569
drv->name = de->driver_name;
4570
if (de->extended_marker == ERL_DRV_EXTENDED_MARKER) {
4571
drv->version.major = de->major_version;
4572
drv->version.minor = de->minor_version;
4573
drv->flags = de->driver_flags;
4576
drv->version.major = 0;
4577
drv->version.minor = 0;
4580
drv->handle = handle;
4582
if (drv->flags & ERL_DRV_FLAG_USE_PORT_LOCKING)
4585
drv->lock = erts_alloc(ERTS_ALC_T_DRIVER_LOCK,
4586
sizeof(erts_smp_mtx_t));
4587
erts_smp_mtx_init_x(drv->lock,
4589
#if defined(ERTS_ENABLE_LOCK_CHECK) || defined(ERTS_ENABLE_LOCK_COUNT)
4590
am_atom_put(drv->name, sys_strlen(drv->name))
4599
drv->start = de->start;
4600
drv->stop = de->stop;
4601
drv->finish = de->finish;
4602
drv->flush = de->flush;
4603
drv->output = de->output ? de->output : no_output_callback;
4604
drv->outputv = de->outputv;
4605
drv->control = de->control;
4606
drv->call = de->call;
4607
drv->event = de->event ? de->event : no_event_callback;
4608
drv->ready_input = de->ready_input ? de->ready_input : no_ready_input_callback;
4609
drv->ready_output = de->ready_output ? de->ready_output : no_ready_output_callback;
4610
drv->timeout = de->timeout ? de->timeout : no_timeout_callback;
4611
drv->ready_async = de->ready_async;
4612
if (de->extended_marker == ERL_DRV_EXTENDED_MARKER)
4613
drv->process_exit = de->process_exit;
4615
drv->process_exit = NULL;
4622
res = (*de->init)();
4629
erts_destroy_driver(erts_driver_t *drv)
4633
erts_smp_mtx_destroy(drv->lock);
4634
erts_free(ERTS_ALC_T_DRIVER_LOCK, drv->lock);
4637
erts_free(ERTS_ALC_T_DRIVER, drv);
4632
4641
* Functions for maintaining a list of driver_entry struct
4640
4649
* Ignore result of erts_add_driver_entry, the init is not
4641
4650
* allowed to fail when drivers are added by drivers.
4643
erts_add_driver_entry(drv,rec_lock != NULL);
4652
erts_add_driver_entry(drv, NULL, rec_lock != NULL);
4646
int erts_add_driver_entry(ErlDrvEntry *drv, int driver_list_locked)
4655
int erts_add_driver_entry(ErlDrvEntry *de, DE_Handle *handle, int driver_list_locked)
4648
DE_List *p = erts_alloc(ERTS_ALC_T_DRV_ENTRY_LIST, sizeof(DE_List));
4657
erts_driver_t *dp = erts_alloc(ERTS_ALC_T_DRIVER, sizeof(erts_driver_t));
4651
4660
if (!driver_list_locked) {
4652
4661
erts_smp_mtx_lock(&erts_driver_list_lock);
4655
init_de_list(p, drv, drv->handle);
4657
p->next = driver_list;
4664
dp->next = driver_list;
4658
4666
if (driver_list != NULL) {
4659
driver_list->prev = p;
4667
driver_list->prev = dp;
4663
4671
if (!driver_list_locked) {
4664
4672
erts_smp_tsd_set(driver_list_lock_status_key, (void *) 1);
4666
if (drv->init != NULL) {
4667
res = (*drv->init)();
4675
res = init_driver(dp, de, handle);
4669
4677
if (res != 0) {
4671
4679
* Remove it all again...
4673
driver_list = p->next;
4681
driver_list = dp->next;
4674
4682
if (driver_list != NULL) {
4675
4683
driver_list->prev = NULL;
4678
if (p->driver_lock) {
4679
erts_smp_mtx_destroy(p->driver_lock);
4680
erts_free(ERTS_ALC_T_DRIVER_LOCK, p->driver_lock);
4683
erts_free(ERTS_ALC_T_DRV_ENTRY_LIST,p);
4685
erts_destroy_driver(dp);
4686
4688
if (!driver_list_locked) {
4693
4695
/* Not allowed for dynamic drivers */
4694
int remove_driver_entry(drv)
4696
int remove_driver_entry(ErlDrvEntry *drv)
4698
4699
void *rec_lock;
4700
4701
rec_lock = erts_smp_tsd_get(driver_list_lock_status_key);
4701
4702
if (rec_lock == NULL) {
4702
4703
erts_smp_mtx_lock(&erts_driver_list_lock);
4705
while (p != NULL && p->drv != drv) {
4709
if (p->de_hndl != NULL) {
4706
while (dp && dp->entry != drv)
4710
4710
if (rec_lock == NULL) {
4711
4711
erts_smp_mtx_unlock(&erts_driver_list_lock);
4715
if (p->prev == NULL) {
4716
driver_list = p->next;
4715
if (dp->prev == NULL) {
4716
driver_list = dp->next;
4718
p->prev->next = p->next;
4720
if (p->next != NULL) {
4721
p->next->prev = p->prev;
4724
if (p->driver_lock) {
4725
erts_smp_mtx_destroy(p->driver_lock);
4726
erts_free(ERTS_ALC_T_DRIVER_LOCK, p->driver_lock);
4729
erts_free(ERTS_ALC_T_DRV_ENTRY_LIST, (void *) p);
4718
dp->prev->next = dp->next;
4720
if (dp->next != NULL) {
4721
dp->next->prev = dp->prev;
4723
erts_destroy_driver(dp);
4730
4724
if (rec_lock == NULL) {
4731
4725
erts_smp_mtx_unlock(&erts_driver_list_lock);