~rdoering/ubuntu/karmic/erlang/fix-535090

« back to all changes in this revision

Viewing changes to erts/emulator/beam/io.c

  • Committer: Bazaar Package Importer
  • Author(s): Sergei Golovan
  • Date: 2009-02-15 16:42:52 UTC
  • mfrom: (3.1.2 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090215164252-q5x4rcf8a5pbesb1
Tags: 1:12.b.5-dfsg-2
Upload to unstable after lenny is released.

Show diffs side-by-side

added added

removed removed

Lines of Context:
46
46
extern ErlDrvEntry spawn_driver_entry;
47
47
extern ErlDrvEntry *driver_tab[]; /* table of static drivers, only used during initialization */
48
48
 
49
 
DE_List*   driver_list;        /* List of all drivers, static and dynamic. */
 
49
erts_driver_t *driver_list; /* List of all drivers, static and dynamic. */
50
50
erts_smp_mtx_t erts_driver_list_lock; /* Mutex for driver list */
51
51
static erts_smp_tsd_key_t driver_list_lock_status_key; /*stop recursive locks when calling 
52
52
                                                         driver init */
63
63
 
64
64
const ErlDrvTermData driver_term_nil = (ErlDrvTermData)NIL;
65
65
 
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;
69
69
 
 
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 *);
73
73
 
74
74
static ERTS_INLINE ErlIOQueue*
75
75
drvport2ioq(ErlDrvPort drvport)
87
87
}
88
88
 
89
89
static ERTS_INLINE int
 
90
is_port_ioq_empty(Port *pp)
 
91
{
 
92
    int res;
 
93
    ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));
 
94
    if (!pp->port_data_lock)
 
95
        res = pp->ioq.size == 0;
 
96
    else {
 
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);
 
101
    }
 
102
    return res;
 
103
}
 
104
 
 
105
int
90
106
erts_is_port_ioq_empty(Port *pp)
91
107
{
92
 
    int res;
93
 
    ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));
94
 
    if (!pp->port_data_lock)
95
 
        res = pp->ioq.size == 0;
96
 
    else {
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);
101
 
    }
102
 
    return res;
 
108
    return is_port_ioq_empty(pp);
103
109
}
104
110
 
105
111
Uint
177
183
}
178
184
#endif
179
185
 
180
 
static ERTS_INLINE erts_smp_mtx_t *
181
 
get_driver_lock(ErlDrvEntry *driver)
182
 
{
183
 
    ASSERT(((DE_List *) driver->handle2) != NULL);
184
 
    ASSERT(((DE_List *) driver->handle2)->drv == driver);
185
 
    return ((DE_List *) driver->handle2)->driver_lock;
186
 
}
187
 
 
188
186
#endif /* #ifdef ERTS_SMP */
189
187
 
190
188
static int
300
298
    Uint32 port_specific;
301
299
    erts_smp_mtx_t *mtx;
302
300
#endif
303
 
    ErlDrvEntry *driver;
 
301
    erts_driver_t *driver;
 
302
 
 
303
    erts_smp_port_tab_lock();
304
304
 
305
305
    ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
306
306
    driver = prt->drv_ptr;
308
308
    ASSERT(driver);
309
309
 
310
310
#ifdef ERTS_SMP
311
 
    erts_smp_port_tab_lock();
312
311
 
313
312
    ASSERT(prt->status & ERTS_PORT_SFLG_FREE_SCHEDULED);
314
313
    ERTS_SMP_LC_ASSERT(erts_smp_atomic_read(&prt->refc) == 0);
391
390
 
392
391
 
393
392
static void
394
 
setup_port(int port_num, Eterm pid, ErlDrvEntry *driver, 
 
393
setup_port(int port_num, Eterm pid, erts_driver_t *driver, 
395
394
           ErlDrvData drv_data, char *name, Uint32 xstatus)
396
395
{
397
396
    Port* prt = &erts_port[port_num];
412
411
    prt->status = ERTS_PORT_SFLG_CONNECTED | xstatus;
413
412
    old_name = prt->name;
414
413
    prt->name = new_name;
 
414
    ASSERT(!prt->drv_ptr);
 
415
    prt->drv_ptr = driver;
415
416
    erts_smp_port_tab_unlock();
416
417
    erts_smp_tasks_unlock();
417
418
#ifdef ERTS_SMP
423
424
 
424
425
    prt->control_flags = 0;
425
426
    prt->connected = pid;
426
 
    ASSERT(!prt->drv_ptr);
427
 
    prt->drv_ptr = driver;
428
427
    prt->drv_data = (long) drv_data;
429
428
    prt->bytes_in = 0;
430
429
    prt->bytes_out = 0;
480
479
   The driver start function must obey the same conventions.
481
480
*/
482
481
int
483
 
erts_open_driver(ErlDrvEntry* driver,   /* Pointer to driver entry. */
 
482
erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */
484
483
                 Eterm pid,             /* Current process. */
485
484
                 char* name,            /* Driver name. */
486
485
                 SysDriverOpts* opts,   /* Options. */
508
507
                                                 << port_extra_shift));
509
508
 
510
509
    erts_smp_mtx_lock(&erts_driver_list_lock);
511
 
    if (driver == &spawn_driver_entry) {
 
510
    if (!driver) {
 
511
        for (driver = driver_list; driver; driver = driver->next) {
 
512
            if (sys_strcmp(driver->name, name) == 0)
 
513
                break;
 
514
        }
 
515
        if (!driver) { 
 
516
            if (error_number_ptr)
 
517
                *error_number_ptr = BADARG;
 
518
            return -3;
 
519
        }
 
520
    }
 
521
    if (driver == &spawn_driver) {
512
522
        char *p;
513
 
        DE_List *de;
 
523
        erts_driver_t *d;
514
524
 
515
525
        /*
516
526
         * Dig out the name of the driver or port program.
529
539
         * if not found.
530
540
         */
531
541
         
532
 
        for (de = driver_list; de != NULL; de = de->next) {
533
 
            if (strcmp(de->drv->driver_name, name) == 0 && erts_ddll_driver_ok(de->de_hndl)) {
534
 
                driver = de->drv;
 
542
        for (d = driver_list; d; d = d->next) {
 
543
            if (strcmp(d->name, name) == 0 && erts_ddll_driver_ok(d->handle)) {
 
544
                driver = d;
535
545
                break;
536
546
            }
537
547
        }
539
549
            *p = ' ';
540
550
    }
541
551
 
542
 
    if (driver != &spawn_driver_entry && opts->exit_status) {
 
552
    if (driver != &spawn_driver && opts->exit_status) {
543
553
        erts_smp_mtx_unlock(&erts_driver_list_lock);
544
554
        if (error_number_ptr) {
545
555
            *error_number_ptr = BADARG;
554
564
 
555
565
#ifdef ERTS_SMP
556
566
    ASSERT(!erts_port[port_num].lock);
557
 
    erts_port[port_num].lock = get_driver_lock(driver);
 
567
    erts_port[port_num].lock = driver->lock;
558
568
    if (!erts_port[port_num].lock) {
559
569
        erts_port[port_num].lock = erts_alloc(ERTS_ALC_T_PORT_LOCK,
560
570
                                              sizeof(erts_smp_mtx_t));
590
600
            trace_sched_ports_where(port, am_in, am_start);
591
601
        }
592
602
        erts_port[port_num].caller = pid;
 
603
        erts_block_fpe();
593
604
        drv_data = (*driver->start)((ErlDrvPort)port_num, name, opts);
 
605
        erts_unblock_fpe();
594
606
        erts_port[port_num].caller = NIL;
595
607
        if (IS_TRACED_FL(port, F_TRACE_SCHED_PORTS)) {
596
608
            trace_sched_ports_where(port, am_out, am_start);
726
738
    Port *port;
727
739
};
728
740
 
729
 
ERTS_SMP_QUALLOC_IMPL(xports_list, ErtsXPortsList, 10, ERTS_ALC_T_XPORTS_LIST)
 
741
ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(xports_list, ErtsXPortsList, 50, ERTS_ALC_T_XPORTS_LIST)
730
742
 
731
743
#endif
732
744
 
742
754
                   ErlDrvData drv_data)   /* Driver data */
743
755
{
744
756
    Port *creator_port;
745
 
    ErlDrvEntry *driver;
 
757
    erts_driver_t *driver;
746
758
    Process *rp;
747
759
    int port_num;
748
760
    Eterm port_id;
782
794
#ifdef ERTS_SMP
783
795
 
784
796
    ASSERT(!erts_port[port_num].lock);
785
 
    erts_port[port_num].lock = get_driver_lock(driver);
 
797
    erts_port[port_num].lock = driver->lock;
786
798
    if (!erts_port[port_num].lock) {
787
799
        ErtsXPortsList *xplp = xports_list_alloc();
788
800
        xplp->port = &erts_port[port_num];
1116
1128
int erts_write_to_port(Eterm caller_id, Port *p, Eterm list)
1117
1129
{
1118
1130
    char *buf;
1119
 
    ErlDrvEntry *drv = p->drv_ptr;
 
1131
    erts_driver_t *drv = p->drv_ptr;
1120
1132
    int size;
1121
1133
    
1122
1134
    ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p));
1180
1192
        ev.size = size;  /* total size */
1181
1193
        ev.iov = ivp;
1182
1194
        ev.binv = bvp;
 
1195
        erts_block_fpe();
1183
1196
        (*drv->outputv)((ErlDrvData)p->drv_data, &ev);
 
1197
        erts_unblock_fpe();
1184
1198
        if (ivp != iv) {
1185
1199
            erts_free(ERTS_ALC_T_TMP, (void *) ivp);
1186
1200
        }
1199
1213
 
1200
1214
        if (r >= 0) {
1201
1215
            size -= r;
1202
 
            if (drv->output) {
1203
 
                (*drv->output)((ErlDrvData)p->drv_data, buf, size);
1204
 
            }
 
1216
            erts_block_fpe();
 
1217
            (*drv->output)((ErlDrvData)p->drv_data, buf, size);
 
1218
            erts_unblock_fpe();
1205
1219
            erts_free(ERTS_ALC_T_TMP, buf);
1206
1220
        }
1207
1221
        else if (r == -2) {
1222
1236
             */
1223
1237
            buf = erts_alloc(ERTS_ALC_T_TMP, size+1); 
1224
1238
            r = io_list_to_buf(list, buf, size);
1225
 
            if (drv->output) {
1226
 
                (*drv->output)((ErlDrvData)p->drv_data, buf, size);
1227
 
            }
 
1239
            erts_block_fpe();
 
1240
            (*drv->output)((ErlDrvData)p->drv_data, buf, size);
 
1241
            erts_unblock_fpe();
1228
1242
            erts_free(ERTS_ALC_T_TMP, buf);
1229
1243
        }
1230
1244
    }
1331
1345
    erts_smp_tsd_set(driver_list_lock_status_key, (void *) 1);
1332
1346
    erts_smp_mtx_lock(&erts_driver_list_lock);
1333
1347
 
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++) {
1344
1352
        drv = *dp;
1345
 
        erts_add_driver_entry(*dp, 1);  /* will call init as well! */
 
1353
        erts_add_driver_entry(*dp, NULL, 1);
1346
1354
    }
1347
1355
 
1348
1356
    erts_smp_tsd_set(driver_list_lock_status_key, NULL);
1829
1837
        if (IS_TRACED_FL(p, F_TRACE_SCHED_PORTS)) {
1830
1838
            trace_sched_ports_where(p, am_in, am_flush);
1831
1839
        }
 
1840
        erts_block_fpe();
1832
1841
        (*p->drv_ptr->flush)((ErlDrvData)p->drv_data);
 
1842
        erts_unblock_fpe();
1833
1843
        if (IS_TRACED_FL(p, F_TRACE_SCHED_PORTS)) {
1834
1844
            trace_sched_ports_where(p, am_out, am_flush);
1835
1845
        }
1839
1849
        ASSERT(!p->xports);
1840
1850
#endif
1841
1851
    }
1842
 
    if ((p->status & ERTS_PORT_SFLGS_DEAD) == 0 && erts_is_port_ioq_empty(p)) {
 
1852
    if ((p->status & ERTS_PORT_SFLGS_DEAD) == 0 && is_port_ioq_empty(p)) {
1843
1853
        terminate_port(p);
1844
1854
    }
1845
1855
}
1850
1860
{
1851
1861
    Eterm send_closed_port_id;
1852
1862
    Eterm connected_id = NIL /* Initialize to silence compiler */;
1853
 
    ErlDrvEntry *drv;
 
1863
    erts_driver_t *drv;
1854
1864
 
1855
1865
    ERTS_SMP_CHK_NO_PROC_LOCKS;
1856
1866
    ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
1875
1885
 
1876
1886
    drv = prt->drv_ptr;
1877
1887
    if ((drv != NULL) && (drv->stop != NULL)) {
 
1888
        erts_block_fpe();
1878
1889
        (*drv->stop)((ErlDrvData)prt->drv_data);
 
1890
        erts_unblock_fpe();
1879
1891
#ifdef ERTS_SMP
1880
1892
        if (prt->xports)
1881
1893
            erts_smp_xports_unlock(prt);
1910
1922
    ASSERT(prt->dist_entry == NULL);
1911
1923
}
1912
1924
 
 
1925
void
 
1926
erts_terminate_port(Port *pp)
 
1927
{
 
1928
    terminate_port(pp);
 
1929
}
 
1930
 
1913
1931
static void sweep_one_monitor(ErtsMonitor *mon, void *vpsc)
1914
1932
{
1915
1933
    ErtsMonitor *rmon;
2055
2073
       erts_port_status_band_set(p, ~ERTS_PORT_SFLG_DISTRIBUTION);
2056
2074
   }
2057
2075
       
2058
 
   if ((reason != am_kill) && !erts_is_port_ioq_empty(p)) {
 
2076
   if ((reason != am_kill) && !is_port_ioq_empty(p)) {
2059
2077
       erts_port_status_bandor_set(p,
2060
2078
                                   ~ERTS_PORT_SFLG_EXITING, /* must turn it off */
2061
2079
                                   ERTS_PORT_SFLG_CLOSING);
2222
2240
     */
2223
2241
 
2224
2242
    port_resp = port_result;
 
2243
    erts_block_fpe();
2225
2244
    n = control((ErlDrvData)prt->drv_data, command, (char*)to_port, to_len,
2226
2245
                &port_resp, sizeof(port_result));
 
2246
    erts_unblock_fpe();
2227
2247
    if (must_free) {
2228
2248
        erts_free(ERTS_ALC_T_TMP, (void *) to_port);
2229
2249
    }
2331
2351
    if (p->reg != NULL)
2332
2352
        erts_print(to, arg, "Registered as: %T\n", p->reg->name);
2333
2353
 
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);
2340
2360
    } else {
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));
2428
2448
 
2429
2449
    p->caller = NIL;
2430
 
    if (p->drv_ptr->output != NULL) {
2431
 
        (*p->drv_ptr->output)((ErlDrvData)p->drv_data, (char*)buf, len);
2432
 
    }
2433
 
}
2434
 
 
2435
 
static void missing_drv_callback(Port *p, ErlDrvEvent hndl, int mode);
2436
 
 
2437
 
void
2438
 
erts_port_ready_input(Port *p, ErlDrvEvent hndl)
2439
 
{
2440
 
    ERTS_SMP_CHK_NO_PROC_LOCKS;
2441
 
    ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p));
2442
 
 
2443
 
    ASSERT((p->status & ERTS_PORT_SFLGS_DEAD) == 0);
2444
 
 
2445
 
    if (!p->drv_ptr->ready_input)
2446
 
        missing_drv_callback(p, hndl, DO_READ);
2447
 
    else {
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)) {
2451
 
            terminate_port(p);
2452
 
        }
2453
 
    }
2454
 
}
2455
 
 
2456
 
void
2457
 
erts_port_ready_output(Port *p, ErlDrvEvent hndl)
2458
 
{
2459
 
    ERTS_SMP_CHK_NO_PROC_LOCKS;
2460
 
    ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p));
2461
 
 
2462
 
    ASSERT((p->status & ERTS_PORT_SFLGS_DEAD) == 0);
2463
 
 
2464
 
    if (!p->drv_ptr->ready_output)
2465
 
        missing_drv_callback(p, hndl, DO_WRITE);
2466
 
    else {
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)) {
2469
 
            terminate_port(p);
2470
 
        }
2471
 
    }
 
2450
    erts_block_fpe();
 
2451
    (*p->drv_ptr->output)((ErlDrvData)p->drv_data, (char*)buf, len);
 
2452
    erts_unblock_fpe();
2472
2453
}
2473
2454
 
2474
2455
int async_ready(Port *p, void* data)
2489
2470
            ASSERT(!p->xports);
2490
2471
#endif
2491
2472
        }
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);
2494
2475
        }
2495
2476
    }
2496
2477
    return need_free;
2497
2478
}
2498
2479
 
2499
 
void
2500
 
erts_port_ready_event(Port* p, ErlDrvEvent hndl, ErlDrvEventData event_data)
2501
 
{
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);
2505
 
 
2506
 
    if (!p->drv_ptr->event) {
2507
 
        missing_drv_callback(p, hndl, 0);
2508
 
    } else {
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)) {
2511
 
            terminate_port(p);
2512
 
        }
2513
 
    }
2514
 
}
2515
 
 
2516
2480
static void
2517
 
missing_drv_callback(Port *p, ErlDrvEvent hndl, int mode)
 
2481
report_missing_drv_callback(Port *p, char *drv_type, char *callback)
2518
2482
{
2519
2483
    ErtsPortNames *pnp = erts_get_port_names(p->id);
2520
 
    char *type;
2521
 
    char *callback;
2522
 
    erts_dsprintf_buf_t *dsbufp;
2523
 
 
2524
 
    switch (mode) {
2525
 
    case DO_READ|DO_WRITE:
2526
 
        type = "Input/Output";
2527
 
        callback = "->ready_input()/->ready_output()";
2528
 
        goto deselect;
2529
 
    case DO_WRITE:
2530
 
        type = "Output";
2531
 
        callback = "->ready_output()";
2532
 
        goto deselect;
2533
 
    case DO_READ:
2534
 
        type = "Input";
2535
 
        callback = "->ready_input()";
2536
 
    deselect:
2537
 
        driver_select((ErlDrvPort) internal_port_index(p->id), hndl, mode, 0);
2538
 
        break;
2539
 
    default:
2540
 
        type = "Event";
2541
 
        callback = "event";
2542
 
        driver_event((ErlDrvPort) internal_port_index(p->id), hndl, NULL);
2543
 
        break;
2544
 
    }
2545
 
 
2546
 
    dsbufp = erts_create_logger_dsbuf();    
2547
 
    erts_dsprintf(dsbufp,
2548
 
                  "%T: %s driver %s %s%s%s does not implement %s!\n", 
2549
 
                  p->id,
2550
 
                  type,
2551
 
                  pnp->driver_name ? pnp->driver_name : "<unknown>",
2552
 
                  pnp->name ? "(" : "",
2553
 
                  pnp->name ? p->name : "",
2554
 
                  pnp->name ? ") " : "",
2555
 
                  callback);
 
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);
2558
2494
}
2559
2495
 
2560
 
 
2561
2496
void
2562
2497
erts_stale_drv_select(Eterm port,
2563
2498
                      ErlDrvEvent hndl,
2636
2571
                name = erts_port[ix].name;
2637
2572
                len = nlen = name ? sys_strlen(name) + 1 : 0;
2638
2573
                driver_name = (erts_port[ix].drv_ptr
2639
 
                               ? erts_port[ix].drv_ptr->driver_name
 
2574
                               ? erts_port[ix].drv_ptr->name
2640
2575
                               : NULL);
2641
2576
                len += driver_name ? sys_strlen(driver_name) + 1 : 0;
2642
2577
            }
2689
2624
                                   NULL);
2690
2625
}
2691
2626
 
2692
 
void
2693
 
erts_port_ready_timeout(Port *p)
2694
 
{
2695
 
    /* timer wrapper MUST check for closing */
2696
 
    ErlDrvEntry* drv;
2697
 
 
2698
 
    ERTS_SMP_CHK_NO_PROC_LOCKS;
2699
 
    ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p));
2700
 
 
2701
 
    drv = p->drv_ptr;
2702
 
 
2703
 
    if (!(p->status & ERTS_PORT_SFLGS_DEAD) && drv->timeout) {
2704
 
        (*drv->timeout)((ErlDrvData)p->drv_data);
2705
 
        if ((p->status & ERTS_PORT_SFLG_CLOSING) && erts_is_port_ioq_empty(p)) {
2706
 
            terminate_port(p);
2707
 
        }
2708
 
    }
2709
 
}
2710
 
 
2711
2627
ErlDrvTermData driver_mk_term_nil(void)
2712
2628
{
2713
2629
    return driver_term_nil;
4280
4196
    callback = prt->drv_ptr->process_exit;
4281
4197
    ASSERT(callback != NULL);
4282
4198
    ref_to_driver_monitor(ref,&drv_monitor);
 
4199
    erts_block_fpe();
4283
4200
    (*callback)((ErlDrvData) (prt->drv_data), &drv_monitor);
 
4201
    erts_unblock_fpe();
4284
4202
    /* remove monitor *after* callback */
4285
4203
    rmon = erts_remove_monitor(&(prt->monitors),ref);
4286
4204
    if (rmon) {
4439
4357
        erts_smp_mtx_unlock(&erts_driver_list_lock);
4440
4358
        return -1;
4441
4359
    }
4442
 
    erts_ddll_lock_driver(dh, prt->drv_ptr->driver_name);
 
4360
    erts_ddll_lock_driver(dh, prt->drv_ptr->name);
4443
4361
    erts_smp_mtx_unlock(&erts_driver_list_lock);
4444
4362
    return 0;
4445
4363
}
4536
4454
    return res;
4537
4455
}
4538
4456
 
4539
 
static void
4540
 
init_de_list(DE_List *de_list, ErlDrvEntry *drv, DE_Handle *de_hndl)
4541
 
{
4542
 
    de_list->next = NULL;
4543
 
    de_list->prev = NULL;
4544
 
 
4545
 
    de_list->drv = drv;
4546
 
    drv->handle2 = (void *) de_list;
4547
 
    de_list->de_hndl = de_hndl;
4548
 
 
4549
 
#ifdef ERTS_SMP
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;
4553
 
    }
4554
 
    else {
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,
4558
 
                            "driver_lock",
4559
 
#ifdef ERTS_ENABLE_LOCK_CHECK
4560
 
                            am_atom_put(drv->driver_name,
4561
 
                                        sys_strlen(drv->driver_name))
4562
 
#else
4563
 
                            NIL
4564
 
#endif
4565
 
            );
4566
 
    }
4567
 
#endif
4568
 
 
4569
 
}
4570
 
 
4571
4457
 
4572
4458
#define ERL_DRV_SYS_INFO_SIZE(LAST_FIELD) \
4573
4459
  (((size_t) &((ErlDrvSysInfo *) 0)->LAST_FIELD) \
4622
4508
     */
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;
4626
 
    }
4627
 
 
4628
 
}
4629
 
 
 
4511
        sip->scheduler_threads = erts_no_schedulers;
 
4512
    }
 
4513
 
 
4514
}
 
4515
 
 
4516
 
 
4517
static ERTS_INLINE Port *
 
4518
get_current_port(void)
 
4519
{
 
4520
    ErtsSchedulerData *esdp = erts_get_scheduler_data();
 
4521
    ASSERT(esdp);
 
4522
    ASSERT(esdp->current_port);
 
4523
    return esdp->current_port;
 
4524
}
 
4525
 
 
4526
/*
 
4527
 * Default callbacks used if not supplied by driver.
 
4528
 */
 
4529
 
 
4530
static void
 
4531
no_output_callback(ErlDrvData drv_data, char *buf, int len)
 
4532
{
 
4533
 
 
4534
}
 
4535
 
 
4536
static void
 
4537
no_event_callback(ErlDrvData drv_data, ErlDrvEvent event, ErlDrvEventData event_data)
 
4538
{
 
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);
 
4542
}
 
4543
 
 
4544
static void
 
4545
no_ready_input_callback(ErlDrvData drv_data, ErlDrvEvent event)
 
4546
{
 
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);
 
4550
}
 
4551
 
 
4552
static void
 
4553
no_ready_output_callback(ErlDrvData drv_data, ErlDrvEvent event)
 
4554
{
 
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);
 
4558
}
 
4559
 
 
4560
static void
 
4561
no_timeout_callback(ErlDrvData drv_data)
 
4562
{
 
4563
 
 
4564
}
 
4565
 
 
4566
static int
 
4567
init_driver(erts_driver_t *drv, ErlDrvEntry *de, DE_Handle *handle)
 
4568
{
 
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;
 
4574
    }
 
4575
    else {
 
4576
        drv->version.major = 0;
 
4577
        drv->version.minor = 0;
 
4578
        drv->flags = 0;
 
4579
    }
 
4580
    drv->handle = handle;
 
4581
#ifdef ERTS_SMP
 
4582
    if (drv->flags & ERL_DRV_FLAG_USE_PORT_LOCKING)
 
4583
        drv->lock = NULL;
 
4584
    else {
 
4585
        drv->lock = erts_alloc(ERTS_ALC_T_DRIVER_LOCK,
 
4586
                               sizeof(erts_smp_mtx_t));
 
4587
        erts_smp_mtx_init_x(drv->lock,
 
4588
                            "driver_lock",
 
4589
#if defined(ERTS_ENABLE_LOCK_CHECK) || defined(ERTS_ENABLE_LOCK_COUNT)
 
4590
                            am_atom_put(drv->name, sys_strlen(drv->name))
 
4591
#else
 
4592
                            NIL
 
4593
#endif
 
4594
            );
 
4595
    }
 
4596
#endif
 
4597
    drv->entry = de;
 
4598
 
 
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;
 
4614
    else
 
4615
        drv->process_exit = NULL;
 
4616
 
 
4617
    if (!de->init)
 
4618
        return 0;
 
4619
    else {
 
4620
        int res;
 
4621
        erts_block_fpe();
 
4622
        res = (*de->init)();
 
4623
        erts_unblock_fpe();
 
4624
        return res;
 
4625
    }
 
4626
}
 
4627
 
 
4628
void
 
4629
erts_destroy_driver(erts_driver_t *drv)
 
4630
{
 
4631
#ifdef ERTS_SMP
 
4632
    if (drv->lock) {
 
4633
        erts_smp_mtx_destroy(drv->lock);
 
4634
        erts_free(ERTS_ALC_T_DRIVER_LOCK, drv->lock);
 
4635
    }
 
4636
#endif    
 
4637
    erts_free(ERTS_ALC_T_DRIVER, drv);
 
4638
}
4630
4639
 
4631
4640
/* 
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.
4642
4651
     */
4643
 
    erts_add_driver_entry(drv,rec_lock != NULL); 
 
4652
    erts_add_driver_entry(drv, NULL, rec_lock != NULL); 
4644
4653
}
4645
4654
 
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)
4647
4656
{
4648
 
    DE_List *p = erts_alloc(ERTS_ALC_T_DRV_ENTRY_LIST, sizeof(DE_List));
4649
 
    int res = 0;
 
4657
    erts_driver_t *dp = erts_alloc(ERTS_ALC_T_DRIVER, sizeof(erts_driver_t));
 
4658
    int res;
4650
4659
 
4651
4660
    if (!driver_list_locked) {
4652
4661
        erts_smp_mtx_lock(&erts_driver_list_lock);
4653
4662
    }
4654
4663
 
4655
 
    init_de_list(p, drv, drv->handle);
4656
 
 
4657
 
    p->next = driver_list;
 
4664
    dp->next = driver_list;
 
4665
    dp->prev = NULL;
4658
4666
    if (driver_list != NULL) {
4659
 
        driver_list->prev = p;
 
4667
        driver_list->prev = dp;
4660
4668
    }
4661
 
    driver_list = p;
 
4669
    driver_list = dp;
4662
4670
 
4663
4671
    if (!driver_list_locked) {
4664
4672
        erts_smp_tsd_set(driver_list_lock_status_key, (void *) 1);
4665
4673
    }
4666
 
    if (drv->init != NULL) {
4667
 
        res = (*drv->init)();
4668
 
    }
 
4674
 
 
4675
    res = init_driver(dp, de, handle);
 
4676
 
4669
4677
    if (res != 0) {
4670
4678
        /* 
4671
4679
         * Remove it all again...
4672
4680
         */
4673
 
        driver_list = p->next;
 
4681
        driver_list = dp->next;
4674
4682
        if (driver_list != NULL) {
4675
4683
            driver_list->prev = NULL;
4676
4684
        }
4677
 
#ifdef ERTS_SMP
4678
 
        if (p->driver_lock) {
4679
 
            erts_smp_mtx_destroy(p->driver_lock);
4680
 
            erts_free(ERTS_ALC_T_DRIVER_LOCK, p->driver_lock);
4681
 
        }
4682
 
#endif
4683
 
        erts_free(ERTS_ALC_T_DRV_ENTRY_LIST,p);
 
4685
        erts_destroy_driver(dp);
4684
4686
    }
4685
4687
        
4686
4688
    if (!driver_list_locked) {
4691
4693
}
4692
4694
 
4693
4695
/* Not allowed for dynamic drivers */
4694
 
int remove_driver_entry(drv)
4695
 
    ErlDrvEntry *drv;
 
4696
int remove_driver_entry(ErlDrvEntry *drv)
4696
4697
{
4697
 
    DE_List *p;
 
4698
    erts_driver_t *dp;
4698
4699
    void *rec_lock;
4699
4700
    
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);
4703
4704
    }
4704
 
    p = driver_list;
4705
 
    while (p != NULL && p->drv != drv) {
4706
 
        p = p->next;
4707
 
    }
4708
 
    if (p != NULL) {
4709
 
        if (p->de_hndl != NULL) {
 
4705
    dp = driver_list;
 
4706
    while (dp && dp->entry != drv)
 
4707
        dp = dp->next;
 
4708
    if (dp) {
 
4709
        if (dp->handle) {
4710
4710
            if (rec_lock == NULL) {
4711
4711
                erts_smp_mtx_unlock(&erts_driver_list_lock);
4712
4712
            }
4713
4713
            return -1;
4714
4714
        }
4715
 
        if (p->prev == NULL) {
4716
 
            driver_list = p->next;
 
4715
        if (dp->prev == NULL) {
 
4716
            driver_list = dp->next;
4717
4717
        } else {
4718
 
            p->prev->next = p->next;
4719
 
        }
4720
 
        if (p->next != NULL) {
4721
 
            p->next->prev = p->prev;
4722
 
        }
4723
 
#ifdef ERTS_SMP
4724
 
        if (p->driver_lock) {
4725
 
            erts_smp_mtx_destroy(p->driver_lock);
4726
 
            erts_free(ERTS_ALC_T_DRIVER_LOCK, p->driver_lock);
4727
 
        }
4728
 
#endif
4729
 
        erts_free(ERTS_ALC_T_DRV_ENTRY_LIST, (void *) p);
 
4718
            dp->prev->next = dp->next;
 
4719
        }
 
4720
        if (dp->next != NULL) {
 
4721
            dp->next->prev = dp->prev;
 
4722
        }
 
4723
        erts_destroy_driver(dp);
4730
4724
        if (rec_lock == NULL) {
4731
4725
            erts_smp_mtx_unlock(&erts_driver_list_lock);
4732
4726
        }