~ubuntu-branches/debian/squeeze/erlang/squeeze

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Erlang Packagers, Sergei Golovan
  • Date: 2006-12-03 17:07:44 UTC
  • mfrom: (2.1.11 feisty)
  • Revision ID: james.westby@ubuntu.com-20061203170744-rghjwupacqlzs6kv
Tags: 1:11.b.2-4
[ Sergei Golovan ]
Fixed erlang-base and erlang-base-hipe prerm scripts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ``The contents of this file are subject to the Erlang Public License,
 
2
 * Version 1.1, (the "License"); you may not use this file except in
 
3
 * compliance with the License. You should have received a copy of the
 
4
 * Erlang Public License along with this software. If not, it can be
 
5
 * retrieved via the world wide web at http://www.erlang.org/.
 
6
 * 
 
7
 * Software distributed under the License is distributed on an "AS IS"
 
8
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 
9
 * the License for the specific language governing rights and limitations
 
10
 * under the License.
 
11
 * 
 
12
 * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
 
13
 * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
 
14
 * AB. All Rights Reserved.''
 
15
 * 
 
16
 *     $Id$
 
17
 */
 
18
/*
 
19
 * BIFs belonging to the 'erl_ddll' module together with utilityn functions
 
20
 * for dynameic loading. The actual loading is done in erl_sys_ddll.c in 
 
21
 * respective system dependent directory.
 
22
 * Th drivers are kept record of in two ways. The driver handle is kept 
 
23
 * and accessed in the actual driver structure, while a separate structure
 
24
 * keeps record of the processes accessing it
 
25
 
 
26
 */
 
27
 
 
28
 
 
29
#ifdef HAVE_CONFIG_H
 
30
#  include "config.h"
 
31
#endif
 
32
 
 
33
#include "sys.h"
 
34
#include "erl_vm.h"
 
35
#include "global.h"
 
36
#include "erl_process.h"
 
37
#include "error.h"
 
38
#include "erl_driver.h"
 
39
#include "bif.h"
 
40
#include "big.h"
 
41
#include "dist.h"
 
42
#include "erl_version.h"
 
43
 
 
44
#ifdef ERTS_SMP
 
45
#define DDLL_SMP 1
 
46
#else
 
47
#define DDLL_SMP 0
 
48
#endif
 
49
 
 
50
/*
 
51
 * Local types
 
52
 */
 
53
 
 
54
typedef struct {
 
55
    Eterm pid;
 
56
    Process *proc;
 
57
    Uint status;
 
58
    Uint count;
 
59
} ProcEntryInfo;
 
60
 
 
61
/*
 
62
 * Forward
 
63
 */
 
64
static char *pick_list_or_atom(Eterm name_term);
 
65
static DE_List *lookup_driver(char *name);
 
66
static Eterm mkatom(char *str);
 
67
static void add_proc_loaded(DE_Handle *dh, Process *proc); 
 
68
static void set_driver_reloading(DE_Handle *dh, Process *proc, char *path, char *name, Uint flags);
 
69
static int load_driver_entry(DE_Handle **dhp, char *path, char *name);
 
70
static int do_unload_driver_entry(DE_Handle *dh, Eterm *save_name);
 
71
static int do_load_driver_entry(DE_Handle *dh, char *path, char *name);
 
72
static void unload_driver_entry(DE_Handle *dh);
 
73
static int reload_driver_entry(DE_Handle *dh);
 
74
static int build_proc_info(DE_Handle *dh, ProcEntryInfo **out_pei, Uint filter);
 
75
static DE_ProcEntry *find_proc_entry(DE_Handle *dh, Process *proc, Uint status);
 
76
static void remove_proc_entry(DE_Handle *dh, DE_ProcEntry *pe);
 
77
static int num_procs(DE_Handle *dh, Uint status);
 
78
/*static int num_entries(DE_Handle *dh, Process *proc, Uint status);*/
 
79
static void notify_proc(Process *proc, Eterm ref, Eterm driver_name, 
 
80
                        Eterm type, Eterm tag, int errcode);
 
81
static void notify_all(DE_Handle *dh, char *name, Uint awaiting, Eterm type, Eterm tag);
 
82
static int load_error_need(int code);
 
83
static Eterm build_load_error_hp(Eterm *hp, int code);
 
84
static Eterm build_load_error(Process *p, int code);
 
85
static int errdesc_to_code(Eterm errdesc, int *code /* out */);
 
86
static Eterm add_monitor(Process *p, DE_Handle *dh, Uint status);
 
87
static Eterm notify_when_loaded(Process *p, Eterm name_term, char *name, Uint32 plocks);
 
88
static Eterm notify_when_unloaded(Process *p, Eterm name_term, char *name, Uint32 plocks);
 
89
/*
 
90
 * Try to load. If the driver is OK, add as LOADED.  If the driver is
 
91
 * UNLOAD, change to reload and add as LOADED, there should be no other
 
92
 * LOADED tagged pid's.  If the driver is RELOAD then add/increment as
 
93
 * LOADED (should be some LOADED pid).  If the driver is not present,
 
94
 * really load and add as LOADED {ok,loaded} {ok,pending_driver}
 
95
 * {error, permanent} {error,load_error()}
 
96
 */
 
97
BIF_RETTYPE erl_ddll_try_load_3(Process *p, Eterm path_term, 
 
98
                                Eterm name_term, Eterm options)
 
99
{
 
100
    char *path = NULL;
 
101
    int path_len;
 
102
    char *name = NULL;
 
103
#if DDLL_SMP
 
104
    int have_proc_lock = 1;
 
105
#endif
 
106
    DE_Handle *dh;
 
107
    DE_List *de;
 
108
    int res;
 
109
    Eterm soft_error_term = NIL;
 
110
    Eterm ok_term = NIL;
 
111
    Eterm *hp;
 
112
    Eterm t;
 
113
    int monitor = 0;
 
114
    Eterm l;
 
115
    Uint flags = 0;
 
116
 
 
117
    for(l = options; is_list(l); l =  CDR(list_val(l))) {
 
118
        Eterm opt = CAR(list_val(l));
 
119
        Eterm *tp;
 
120
        if (is_not_tuple(opt)) {
 
121
            goto error;
 
122
        }
 
123
        tp = tuple_val(opt);
 
124
        if (*tp != make_arityval(2) || is_not_atom(tp[1])) {
 
125
            goto error;
 
126
        }
 
127
        switch (tp[1]) {
 
128
        case am_driver_options:
 
129
            {
 
130
                Eterm ll;
 
131
                for(ll = tp[2]; is_list(ll); ll = CDR(list_val(ll))) {
 
132
                    Eterm dopt = CAR(list_val(ll));
 
133
                    if (dopt == am_kill_ports) {
 
134
                        flags |= ERL_DE_FL_KILL_PORTS;
 
135
                    } else {
 
136
                        goto error;
 
137
                    }
 
138
                }
 
139
                if (is_not_nil(ll)) {
 
140
                    goto error;
 
141
                }
 
142
            }
 
143
            break;
 
144
        case am_monitor:
 
145
            if (tp[2] != am_pending_driver && tp[2] != am_pending ) { 
 
146
                goto error;
 
147
            }
 
148
            monitor = 1;
 
149
            break;
 
150
        default:
 
151
            goto error;
 
152
        }
 
153
    }
 
154
    if (is_not_nil(l)) {
 
155
        goto error;
 
156
    }
 
157
 
 
158
 
 
159
    if ((name = pick_list_or_atom(name_term)) == NULL) {
 
160
        goto error;
 
161
    }
 
162
 
 
163
    path_len = io_list_len(path_term);
 
164
 
 
165
    if (path_len <= 0) {
 
166
        goto error;
 
167
    }
 
168
    path = erts_alloc(ERTS_ALC_T_DDLL_TMP_BUF, path_len + 1 /* might need path separator */ + sys_strlen(name) + 1);
 
169
    if (io_list_to_buf(path_term, path, path_len) != 0) {
 
170
        goto error;
 
171
    }
 
172
    while (path_len > 0 && (path[path_len-1] == '\\' || path[path_len-1] == '/')) {
 
173
        --path_len;
 
174
    }
 
175
    path[path_len++] = '/';
 
176
    /*path[path_len] = '\0';*/
 
177
    sys_strcpy(path+path_len,name);
 
178
 
 
179
#if DDLL_SMP
 
180
    erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
 
181
    have_proc_lock = 0;
 
182
    erts_smp_io_lock();
 
183
#endif    
 
184
 
 
185
    if ((de = lookup_driver(name)) != NULL) {
 
186
        if (de->de_hndl == NULL) {
 
187
            /* static_driver */
 
188
            soft_error_term = am_linked_in_driver;
 
189
            goto soft_error;
 
190
        } else {
 
191
            dh = de->de_hndl;
 
192
            if (dh->status == ERL_DE_OK) {
 
193
                /*already loaded and healthy (might be by me) */
 
194
                if (sys_strcmp(dh->full_path, path) || 
 
195
                    (dh->flags & ERL_FL_CONSISTENT_MASK) != (flags &  ERL_FL_CONSISTENT_MASK)) {
 
196
                    soft_error_term = am_inconsistent;
 
197
                    goto soft_error;
 
198
                }
 
199
                add_proc_loaded(dh,p);
 
200
                monitor = 0;
 
201
                ok_term = mkatom("already_loaded");
 
202
            } else if (dh->status == ERL_DE_UNLOAD || dh->status == ERL_DE_FORCE_UNLOAD) {
 
203
                /* Unload requested and granted (no more processes) */
 
204
                set_driver_reloading(dh, p, path, name, flags);
 
205
                ok_term = am_pending_driver;
 
206
            } else if (dh->status == ERL_DE_RELOAD) {
 
207
                if (sys_strcmp(dh->reload_full_path, path) || 
 
208
                    (dh->reload_flags & ERL_FL_CONSISTENT_MASK) != 
 
209
                        (flags &  ERL_FL_CONSISTENT_MASK)) {
 
210
                    soft_error_term = am_inconsistent;
 
211
                    goto soft_error;
 
212
                }
 
213
                /* Load of granted unload... */
 
214
                add_proc_loaded(dh,p);
 
215
                ok_term = am_pending_driver;
 
216
            } else { /* ERL_DE_PERMANENT */
 
217
                soft_error_term = am_permanent;
 
218
                goto soft_error;
 
219
            }
 
220
        }
 
221
    } else {
 
222
        if ((res = load_driver_entry(&dh, path, name)) !=  ERL_DE_NO_ERROR) {
 
223
#if DDLL_SMP
 
224
            /* Need process lock for build_load_error */
 
225
            erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
 
226
            have_proc_lock = 1;
 
227
#endif
 
228
            soft_error_term = build_load_error(p, res);
 
229
            goto soft_error;
 
230
        } else {
 
231
            dh->flags = flags;
 
232
            add_proc_loaded(dh,p);
 
233
            monitor = 0;
 
234
            ok_term = mkatom("loaded");
 
235
        }
 
236
    }
 
237
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
238
#if DDLL_SMP
 
239
    if (!have_proc_lock) {
 
240
        erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
 
241
    }
 
242
#endif
 
243
    p->flags |= F_USING_DDLL;
 
244
    if (monitor) {
 
245
        Eterm mref = add_monitor(p, dh, ERL_DE_PROC_AWAIT_LOAD);
 
246
        hp = HAlloc(p,4);
 
247
        t = TUPLE3(hp, am_ok, ok_term, mref);
 
248
    } else {
 
249
        hp = HAlloc(p,3);
 
250
        t = TUPLE2(hp, am_ok, ok_term);
 
251
    }
 
252
#if DDLL_SMP
 
253
    erts_smp_io_unlock();
 
254
#endif
 
255
    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) path);
 
256
    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
 
257
    BIF_RET(t);
 
258
 soft_error:
 
259
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
260
#if DDLL_SMP
 
261
    erts_smp_io_unlock();
 
262
    if (!have_proc_lock) {
 
263
        erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
 
264
    }
 
265
#endif
 
266
    hp = HAlloc(p,3);
 
267
    t = TUPLE2(hp, am_error, soft_error_term);
 
268
    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) path);
 
269
    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
 
270
    BIF_RET(t);
 
271
 error:
 
272
    ERTS_SMP_LC_ASSERT(!erts_smp_lc_io_is_locked());
 
273
    ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(p));
 
274
    if (path != NULL) {
 
275
        erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) path);
 
276
    }
 
277
    if (name != NULL) {
 
278
        erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
 
279
    }
 
280
    BIF_ERROR(p,BADARG);
 
281
}
 
282
 
 
283
 
 
284
/* 
 
285
   You have to have loaded the driver and the pid state 
 
286
   is LOADED or AWAIT_LOAD. You will be removed from the list
 
287
   regardless of driver state.
 
288
   If the driver is loaded by someone else to, return is
 
289
   {ok, pending_process}
 
290
   If the driver is loaded but locked by a port, return is
 
291
   {ok, pending_driver}
 
292
   If the driver is loaded and free to unload (you're the last holding it)
 
293
   {ok, unloaded}
 
294
   If it's not loaded or not loaded by you
 
295
   {error, not_loaded} or {error, not_loaded_by_you}
 
296
 
 
297
   Internally, if its in state UNLOADING, just return {ok, pending_driver} and
 
298
   remove/decrement this pid (which should be an LOADED tagged one).
 
299
   If the state is RELOADING, this pid should be in list as LOADED tagged, 
 
300
   only AWAIT_LOAD would be possible but not allowed for unloading, remove it 
 
301
   and, if the last LOADED tagged, change from RELOAD to UNLOAD and notify
 
302
   any AWAIT_LOAD-waiters with {'DOWN', ref(), driver, name(), load_cancelled}
 
303
   If the driver made itself permanent, {'UP', ref(), driver, name(), permanent}
 
304
*/
 
305
Eterm erl_ddll_try_unload_2(Process *p, Eterm name_term, Eterm options)
 
306
{
 
307
    char *name = NULL;
 
308
    Eterm ok_term = NIL;
 
309
    Eterm soft_error_term = NIL;
 
310
    DE_List *de;
 
311
    DE_Handle *dh;
 
312
    DE_ProcEntry *pe;
 
313
    Eterm *hp;
 
314
    Eterm t;
 
315
    int monitor = 0;
 
316
    Eterm l;
 
317
    int kill_ports = 0;
 
318
 
 
319
    for(l = options; is_list(l); l =  CDR(list_val(l))) {
 
320
        Eterm opt = CAR(list_val(l));
 
321
        Eterm *tp;
 
322
        if (is_not_tuple(opt)) {
 
323
            if (opt == am_kill_ports) {
 
324
                kill_ports = 1;
 
325
                continue;
 
326
            } else {
 
327
                goto error;
 
328
            }
 
329
        }
 
330
        tp = tuple_val(opt);
 
331
        if (*tp != make_arityval(2) || tp[1] != am_monitor) {
 
332
            goto error;
 
333
        }
 
334
        if (tp[2] == am_pending_driver) { 
 
335
            monitor = 1;
 
336
        } else if (tp[2] == am_pending) {
 
337
            monitor = 2;
 
338
        } else {
 
339
            goto error;
 
340
        }
 
341
    }
 
342
    if (is_not_nil(l)) {
 
343
        goto error;
 
344
    }
 
345
 
 
346
    if ((name = pick_list_or_atom(name_term)) == NULL) {
 
347
        goto error;
 
348
    }
 
349
 
 
350
#if DDLL_SMP
 
351
    erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
 
352
    erts_smp_io_lock();
 
353
#endif    
 
354
 
 
355
    if ((de = lookup_driver(name)) == NULL) {
 
356
        soft_error_term = am_not_loaded;
 
357
        goto soft_error;
 
358
    }
 
359
 
 
360
    if (de->de_hndl == NULL) {
 
361
        soft_error_term = am_linked_in_driver;
 
362
        goto soft_error;
 
363
    } else if (de->de_hndl->status == ERL_DE_PERMANENT) {
 
364
        soft_error_term = am_permanent;
 
365
        goto soft_error;
 
366
    }   
 
367
    dh = de->de_hndl;
 
368
    if (dh->flags & ERL_DE_FL_KILL_PORTS) {
 
369
        kill_ports = 1;
 
370
    }
 
371
    if ((pe = find_proc_entry(dh, p, ERL_DE_PROC_LOADED)) == NULL) {
 
372
        if (num_procs(dh, ERL_DE_PROC_LOADED) > 0) {
 
373
            soft_error_term = am_not_loaded_by_this_process;
 
374
            goto soft_error;
 
375
        }
 
376
    } else {
 
377
        remove_proc_entry(dh, pe);
 
378
        erts_free(ERTS_ALC_T_DDLL_PROCESS, pe);
 
379
    }
 
380
    if (num_procs(dh, ERL_DE_PROC_LOADED) > 0) {
 
381
        ok_term = mkatom("pending_process");
 
382
        --monitor;
 
383
        goto done;
 
384
    }
 
385
    if (dh->port_count > 0) {
 
386
        if (dh->status == ERL_DE_RELOAD) {
 
387
            notify_all(dh, de->drv->driver_name, 
 
388
                       ERL_DE_PROC_AWAIT_LOAD, am_DOWN, am_load_cancelled);
 
389
            erts_free(ERTS_ALC_T_DDLL_HANDLE,dh->reload_full_path);
 
390
            erts_free(ERTS_ALC_T_DDLL_HANDLE,dh->reload_driver_name);
 
391
            dh->reload_full_path = dh->reload_driver_name = NULL; 
 
392
            dh->reload_flags = 0;
 
393
        } 
 
394
        ++kill_ports;
 
395
        dh->status = ERL_DE_UNLOAD;
 
396
        ok_term = am_pending_driver;
 
397
        goto done;
 
398
    }
 
399
    /* Really unload the driver... */
 
400
    ASSERT((dh->status == ERL_DE_OK));
 
401
    /* Might be to myself, but no problem since I will take the process lock then */
 
402
    notify_all(dh, de->drv->driver_name, ERL_DE_PROC_AWAIT_UNLOAD, am_DOWN, am_unloaded);
 
403
    ASSERT((dh->procs == NULL));
 
404
    ASSERT((dh->reload_full_path == NULL));
 
405
    ASSERT((dh->reload_driver_name == NULL));
 
406
    unload_driver_entry(dh);
 
407
    monitor = 0;
 
408
    ok_term = mkatom("unloaded");
 
409
done:
 
410
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
411
#if DDLL_SMP
 
412
    erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
 
413
#endif
 
414
    p->flags |= F_USING_DDLL;
 
415
    if (monitor > 0) {
 
416
        Eterm mref = add_monitor(p, dh, ERL_DE_PROC_AWAIT_UNLOAD);
 
417
        hp = HAlloc(p,4);
 
418
        t = TUPLE3(hp, am_ok, ok_term, mref);
 
419
    } else {
 
420
        hp = HAlloc(p,3);
 
421
        t = TUPLE2(hp, am_ok, ok_term);
 
422
    }
 
423
    if (kill_ports > 1) {
 
424
        int j;
 
425
        int c = dh->port_count;
 
426
#if DDLL_SMP
 
427
        erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
 
428
#endif
 
429
        dh->status = ERL_DE_FORCE_UNLOAD;
 
430
        for (j = 0; j < erts_max_ports && c > 0; j++) {
 
431
            if (erts_port[j].status != FREE &&
 
432
                erts_port[j].drv_ptr->handle == dh) {
 
433
                /* Keep track of ports, driver might be recursively closed */
 
434
                --c;
 
435
                driver_failure_atom(j, "driver_unloaded");
 
436
            }
 
437
        }
 
438
#if DDLL_SMP
 
439
        erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
 
440
#endif
 
441
    } 
 
442
#if DDLL_SMP
 
443
    erts_smp_io_unlock();
 
444
#endif
 
445
    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
 
446
    if (kill_ports > 1) {
 
447
        ERTS_BIF_CHK_EXITED(p); /* May be exited by port killing */
 
448
    }
 
449
    BIF_RET(t);
 
450
 
 
451
soft_error:
 
452
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
453
#if DDLL_SMP
 
454
    erts_smp_io_unlock();
 
455
    erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
 
456
#endif
 
457
    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
 
458
    hp = HAlloc(p,3);
 
459
    t = TUPLE2(hp, am_error, soft_error_term);
 
460
    BIF_RET(t);
 
461
 
 
462
 error: /* No lock fiddling before going here */
 
463
    ERTS_SMP_LC_ASSERT(!erts_smp_lc_io_is_locked());
 
464
    ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(p));
 
465
    if (name != NULL) {
 
466
        erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
 
467
    }
 
468
    BIF_ERROR(p,BADARG);
 
469
}
 
470
 
 
471
 
 
472
/* 
 
473
 * A shadow of the "real" demonitor BIF
 
474
 */
 
475
BIF_RETTYPE erl_ddll_demonitor_1(Process *p, Eterm ref)
 
476
{
 
477
   if (is_not_internal_ref(ref)) {
 
478
       BIF_ERROR(p, BADARG);
 
479
   }
 
480
   if (p->flags & F_USING_DDLL) {
 
481
       erts_ddll_remove_monitor(p, ref, ERTS_PROC_LOCK_MAIN);
 
482
   }
 
483
   BIF_RET(am_true);
 
484
}
 
485
 
 
486
/* 
 
487
 * A shadow of the "real" monitor BIF
 
488
 */
 
489
BIF_RETTYPE erl_ddll_monitor_2(Process *p, Eterm dr, Eterm what)
 
490
{
 
491
    if (dr != am_driver) {
 
492
        BIF_ERROR(p,BADARG);
 
493
    }
 
494
    return erts_ddll_monitor_driver(p, what, ERTS_PROC_LOCK_MAIN);
 
495
}
 
496
 
 
497
/* 
 
498
 * Return list of loaded drivers {ok,[string()]} 
 
499
 */
 
500
Eterm erl_ddll_loaded_drivers_0(Process *p)
 
501
{
 
502
    Eterm *hp;
 
503
    int need = 3;
 
504
    Eterm res = NIL;
 
505
    DE_List *de;
 
506
#if DDLL_SMP
 
507
    if (erts_smp_io_trylock() == EBUSY) {
 
508
        erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
 
509
        erts_smp_io_lock();
 
510
        erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
 
511
    }   
 
512
#endif
 
513
    for (de = driver_list; de != NULL; de = de->next) {
 
514
        need += sys_strlen(de->drv->driver_name)*2+2;
 
515
    }
 
516
    hp = HAlloc(p,need);
 
517
    for (de = driver_list; de != NULL; de = de->next) {
 
518
        Eterm l;
 
519
        l = buf_to_intlist(&hp, de->drv->driver_name, sys_strlen(de->drv->driver_name), NIL);
 
520
        res = CONS(hp,l,res);
 
521
        hp += 2;
 
522
    }
 
523
    res = TUPLE2(hp,am_ok,res);
 
524
    /* hp += 3 */
 
525
#if DDLL_SMP
 
526
    erts_smp_io_unlock();
 
527
#endif
 
528
    BIF_RET(res);
 
529
}
 
530
 
 
531
/* 
 
532
 * More detailed info about loaded drivers: 
 
533
 * item is processes, driver_options, port_count, linked_in_driver, 
 
534
 * permanent, awaiting_load, awaiting_unload 
 
535
 */
 
536
Eterm erl_ddll_info_2(Process *p, Eterm name_term, Eterm item) 
 
537
{
 
538
    char *name = NULL;
 
539
    Eterm res = NIL;
 
540
    DE_List *de;
 
541
    ProcEntryInfo *pei = NULL;
 
542
    int num_pei;
 
543
    Eterm *hp;
 
544
    int i;
 
545
    Uint filter;
 
546
#if DDLL_SMP
 
547
    int have_io_lock = 0;
 
548
#endif
 
549
 
 
550
    if ((name = pick_list_or_atom(name_term)) == NULL) {
 
551
        goto error;
 
552
    }
 
553
 
 
554
    if (!is_atom(item)) {
 
555
        goto error;
 
556
    }
 
557
 
 
558
#if DDLL_SMP 
 
559
    if (erts_smp_io_trylock() == EBUSY) {
 
560
        /* Unlock process locks, and acquire locks in lock order... */
 
561
        erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
 
562
        erts_smp_io_lock();
 
563
        erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
 
564
    }
 
565
    have_io_lock = 1;
 
566
#endif
 
567
    if ((de = lookup_driver(name)) == NULL) {
 
568
        goto error;
 
569
    }
 
570
    
 
571
    switch (item) {
 
572
    case am_processes:
 
573
        filter = ERL_DE_PROC_LOADED;
 
574
        break;
 
575
    case am_driver_options:
 
576
        if (de->de_hndl == NULL) {
 
577
            res = am_linked_in_driver;
 
578
        } else {
 
579
            Uint start_flags = de->de_hndl->flags & ERL_FL_CONSISTENT_MASK;
 
580
            /* Cheating, only one flag for now... */
 
581
            if (start_flags & ERL_DE_FL_KILL_PORTS) {
 
582
                Eterm *myhp;
 
583
                myhp = HAlloc(p,2);
 
584
                res = CONS(myhp,am_kill_ports,NIL);
 
585
            } else {
 
586
                res = NIL;
 
587
            }
 
588
        }
 
589
        goto done;
 
590
    case am_port_count:
 
591
        if (de->de_hndl == NULL) {
 
592
            res = am_linked_in_driver;
 
593
        } else if (de->de_hndl->status == ERL_DE_PERMANENT) {
 
594
            res = am_permanent;
 
595
        } else {
 
596
            res = make_small(de->de_hndl->port_count);
 
597
        }
 
598
        goto done;
 
599
    case am_linked_in_driver:
 
600
        if (de->de_hndl == NULL){
 
601
            res = am_true;
 
602
        } else {
 
603
            res = am_false;
 
604
        }
 
605
        goto done;
 
606
    case am_permanent:
 
607
        if (de->de_hndl != NULL && de->de_hndl->status == ERL_DE_PERMANENT) {
 
608
            res = am_true;
 
609
        } else {
 
610
            res = am_false;
 
611
        }
 
612
        goto done;
 
613
    case am_awaiting_load:
 
614
        filter = ERL_DE_PROC_AWAIT_LOAD;
 
615
        break;
 
616
    case am_awaiting_unload:
 
617
        filter = ERL_DE_PROC_AWAIT_UNLOAD;
 
618
        break;
 
619
    default:
 
620
        goto error;
 
621
    }
 
622
 
 
623
    if (de->de_hndl == NULL) {
 
624
        res = am_linked_in_driver;
 
625
        goto done;
 
626
    } else if (de->de_hndl->status == ERL_DE_PERMANENT) {
 
627
        res = am_permanent;
 
628
        goto done;
 
629
    }
 
630
    num_pei = build_proc_info(de->de_hndl, &pei, filter);
 
631
    if (!num_pei) {
 
632
        goto done;
 
633
    }
 
634
    hp = HAlloc(p,num_pei * (2+3));
 
635
    for (i = 0; i < num_pei; ++ i) {
 
636
        Eterm tpl = TUPLE2(hp,pei[i].pid,make_small(pei[i].count));
 
637
        hp += 3;
 
638
        res = CONS(hp,tpl,res);
 
639
        hp += 2;
 
640
    }    
 
641
 done:    
 
642
#if DDLL_SMP
 
643
    erts_smp_io_unlock();
 
644
#endif
 
645
    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
 
646
    BIF_RET(res);
 
647
 error:
 
648
    if (name != NULL) {
 
649
        erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
 
650
    }
 
651
#if DDLL_SMP
 
652
    if (have_io_lock) {
 
653
        erts_smp_io_unlock();
 
654
    }
 
655
#endif
 
656
    BIF_ERROR(p,BADARG);
 
657
}
 
658
 
 
659
/*
 
660
 * Backend for erl_ddll:format_error, handles all "soft" errors returned by builtins,
 
661
 * possibly by calling the system specific error handler
 
662
 */
 
663
Eterm erl_ddll_format_error_int_1(Process *p, Eterm code_term)
 
664
{
 
665
    char *errstring = NULL;
 
666
    int errint;
 
667
    int len;
 
668
    Eterm ret = NIL;
 
669
    Eterm *hp;
 
670
 
 
671
    /* These errors can only appear in the erlang interface, not in the interface provided
 
672
       to drivers... */
 
673
    switch (code_term) {
 
674
    case am_inconsistent:
 
675
        errstring = "Driver name and/or driver options are inconsistent with "
 
676
            "currently loaded driver";
 
677
        break;
 
678
    case am_linked_in_driver:
 
679
        errstring = "Driver is statically linked and "
 
680
            "cannot be loaded/unloaded";
 
681
        break;
 
682
    case am_permanent:
 
683
        errstring = "DDLL driver is permanent an can not be unloaded/loaded";
 
684
        break;
 
685
    case am_not_loaded:
 
686
        errstring = "DDLL driver is not loaded";
 
687
        break;
 
688
    case am_not_loaded_by_this_process:
 
689
        errstring = "DDLL driver was not loaded by this process";
 
690
        break;
 
691
    case am_not_pending:
 
692
        errstring = "DDLL load not pending for this driver name";
 
693
        break;
 
694
    case am_already_loaded:
 
695
        errstring = "DDLL driver is already loaded successfully";
 
696
        break;
 
697
    case am_unloading:
 
698
        errstring = "Driver is unloading";
 
699
        break;
 
700
    default:
 
701
        /* A "real" error, we translate the atom to a code and translate the code 
 
702
           to a string in the same manner as in the interface provided to drivers... */
 
703
        if (errdesc_to_code(code_term,&errint) != 0) {
 
704
            goto error;
 
705
        }
 
706
#if DDLL_SMP 
 
707
        if (erts_smp_io_trylock() == EBUSY) {
 
708
            /* Unlock process locks, and acquire locks in lock order... */
 
709
            erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
 
710
            erts_smp_io_lock();
 
711
            erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
 
712
        }
 
713
#endif
 
714
        errstring = erts_ddll_error(errint);
 
715
#if DDLL_SMP
 
716
        erts_smp_io_unlock();
 
717
#endif
 
718
        break;
 
719
    }
 
720
    if (errstring == NULL) {
 
721
        goto error;
 
722
    }
 
723
    len = sys_strlen(errstring);
 
724
    hp = HAlloc(p, 2 * len);
 
725
    ret = buf_to_intlist(&hp, errstring, len, NIL);
 
726
    BIF_RET(ret);
 
727
 error:
 
728
    BIF_ERROR(p,BADARG);
 
729
 
730
 
 
731
void erts_ddll_init(void)
 
732
{
 
733
    erl_sys_ddll_init();
 
734
}
 
735
 
 
736
/* Return value as a bif, called by erlang:monitor */
 
737
Eterm erts_ddll_monitor_driver(Process *p, Eterm description, Uint32 plocks) 
 
738
{
 
739
    Eterm *tp;
 
740
    Eterm ret;
 
741
    char *name;
 
742
 
 
743
    if (is_not_tuple(description)) {
 
744
        BIF_ERROR(p,BADARG);
 
745
    }
 
746
    tp = tuple_val(description);
 
747
    if (*tp != make_arityval(2)) {
 
748
        BIF_ERROR(p,BADARG);
 
749
    }
 
750
    if ((name = pick_list_or_atom(tp[1])) == NULL) {
 
751
        BIF_ERROR(p,BADARG);
 
752
    }
 
753
    switch (tp[2]) {
 
754
    case am_loaded:
 
755
        ERTS_BIF_PREP_RET(ret, notify_when_loaded(p,tp[1],name,plocks));
 
756
        break;
 
757
    case am_unloaded:
 
758
        ERTS_BIF_PREP_RET(ret, notify_when_unloaded(p,tp[1],name,plocks));
 
759
        break;
 
760
    default:
 
761
        ERTS_BIF_PREP_ERROR(ret,p,BADARG);
 
762
        break;
 
763
    }
 
764
 
 
765
    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
 
766
    return ret;
 
767
}
 
768
 
 
769
void erts_ddll_remove_monitor(Process *p, Eterm ref, Uint32 plocks)
 
770
 
771
    DE_List *de;
 
772
    erts_smp_proc_unlock(p, plocks);
 
773
    erts_smp_io_lock();
 
774
    de = driver_list;
 
775
    while (de != NULL) {
 
776
        if (de->de_hndl != NULL && de->de_hndl->status != ERL_DE_PERMANENT) {
 
777
            DE_ProcEntry **pe = &(de->de_hndl->procs);
 
778
            while ((*pe) != NULL) {
 
779
                if ((*pe)->proc == p && 
 
780
                    ((*pe)->awaiting_status == ERL_DE_PROC_AWAIT_LOAD ||
 
781
                     (*pe)->awaiting_status == ERL_DE_PROC_AWAIT_UNLOAD) &&
 
782
                    eq(make_internal_ref(&((*pe)->heap)),ref)) {
 
783
                    DE_ProcEntry *r = *pe;
 
784
                    *pe = r->next;
 
785
                    erts_free(ERTS_ALC_T_DDLL_PROCESS, (void *) r);
 
786
                    goto done;
 
787
                } 
 
788
                pe = &((*pe)->next);
 
789
            }
 
790
        }
 
791
        de = de->next;
 
792
    }
 
793
 done:
 
794
    erts_smp_io_unlock();
 
795
    erts_smp_proc_lock(p, plocks);
 
796
}
 
797
 
 
798
/* 
 
799
 * Called from erl_process.c, Need to take the io_lock.
 
800
 */
 
801
void erts_ddll_proc_dead(Process *p, Uint32 plocks) 
 
802
{
 
803
    DE_List **de;
 
804
    erts_smp_proc_unlock(p, plocks);
 
805
    erts_smp_io_lock();
 
806
    de = &driver_list;
 
807
    while (*de != NULL) {
 
808
        if ((*de)->de_hndl != NULL && (*de)->de_hndl->status != ERL_DE_PERMANENT) {
 
809
            DE_ProcEntry **pe = &((*de)->de_hndl->procs);
 
810
            int kill_ports = ((*de)->de_hndl->flags & ERL_DE_FL_KILL_PORTS);
 
811
            int left = 0;
 
812
            while ((*pe) != NULL) {
 
813
                if ((*pe)->proc == p) {
 
814
                    DE_ProcEntry *r = *pe;
 
815
                    *pe = r->next;
 
816
                    erts_free(ERTS_ALC_T_DDLL_PROCESS, (void *) r);
 
817
                } else {
 
818
                    if ((*pe)->awaiting_status == ERL_DE_PROC_LOADED) {
 
819
                        ++left;
 
820
                    }
 
821
                    pe = &((*pe)->next);
 
822
                }
 
823
            }
 
824
            /* Do we have anyone holding the driver? */
 
825
            if (!left && ((*de)->de_hndl->port_count == 0)) {
 
826
                /* Remove driver! */
 
827
                DE_List *q;
 
828
                DE_Handle *dh = (*de)->de_hndl;
 
829
                if (dh->reload_full_path != NULL) {
 
830
                    erts_free(ERTS_ALC_T_DDLL_HANDLE,dh->reload_full_path);
 
831
                }
 
832
                if (dh->reload_driver_name != NULL) {
 
833
                    erts_free(ERTS_ALC_T_DDLL_HANDLE,dh->reload_driver_name);
 
834
                }
 
835
                dh->reload_full_path = dh->reload_driver_name = NULL;           
 
836
                dh->reload_flags = 0;
 
837
                dh->status = ERL_DE_UNLOAD;
 
838
                notify_all(dh, (*de)->drv->driver_name, 
 
839
                           ERL_DE_PROC_AWAIT_LOAD, am_DOWN, am_load_cancelled);
 
840
                notify_all(dh, (*de)->drv->driver_name, 
 
841
                           ERL_DE_PROC_AWAIT_UNLOAD, am_DOWN, am_unloaded);
 
842
                ASSERT(dh->procs == NULL);
 
843
                q = *de;
 
844
                *de = (*de)->next;    
 
845
                if (q->drv->finish) {
 
846
                    (*(q->drv->finish))();
 
847
                }
 
848
                erts_sys_ddll_close(dh->handle);
 
849
                erts_free(ERTS_ALC_T_DRV_ENTRY_LIST, (void *) q);
 
850
                ASSERT(dh->full_path != NULL);
 
851
                erts_free(ERTS_ALC_T_DDLL_HANDLE, dh->full_path);
 
852
                erts_free(ERTS_ALC_T_DDLL_HANDLE, dh);
 
853
            } else {
 
854
                if (!left && ((*de)->de_hndl->port_count > 0)) {
 
855
                    if (kill_ports) {
 
856
                        int j;
 
857
                        int c = (*de)->de_hndl->port_count;
 
858
                        (*de)->de_hndl->status = ERL_DE_FORCE_UNLOAD;
 
859
                        for (j = 0; j < erts_max_ports && c > 0; j++) {
 
860
                            if (erts_port[j].status != FREE &&
 
861
                                erts_port[j].drv_ptr->handle == (*de)->de_hndl) {
 
862
                                /* This might close the driver and hence (*de)
 
863
                                   is reset, that's why we need to keep track 
 
864
                                   of the port count */
 
865
                                --c;
 
866
                                driver_failure_atom(j, "driver_unloaded");
 
867
                            }
 
868
                        }
 
869
                    } else {
 
870
                        (*de)->de_hndl->status = ERL_DE_UNLOAD;
 
871
                    }
 
872
                }
 
873
                de = &((*de)->next);
 
874
            }
 
875
        } else {
 
876
            de = &((*de)->next);
 
877
        }
 
878
    }
 
879
    erts_smp_io_unlock();
 
880
    erts_smp_proc_lock(p, plocks);
 
881
}
 
882
void erts_ddll_lock_driver(DE_Handle *dh, char *name)
 
883
{
 
884
    DE_ProcEntry *p,*q;
 
885
    notify_all(dh, name, 
 
886
               ERL_DE_PROC_AWAIT_LOAD, am_UP, am_permanent);
 
887
    notify_all(dh, name, 
 
888
               ERL_DE_PROC_AWAIT_UNLOAD, am_UP, am_permanent);
 
889
    
 
890
    p = dh->procs; 
 
891
    while(p != NULL) {
 
892
        q = p;
 
893
        p = p->next;
 
894
        erts_free(ERTS_ALC_T_DDLL_PROCESS, (void *) q);
 
895
    }
 
896
    dh->status = ERL_DE_PERMANENT;
 
897
}
 
898
 
 
899
/* The pid list -
 
900
   ERL_DE_PROC_AWAIT_UNLOAD -> Awaiting actual unloading, can be anyone 
 
901
   doing that
 
902
   ERL_DE_PROC_LOADED -> Has requested load and got pending,driver answer
 
903
   ERL_DE_AWAIT_LOAD -> Has managed to request loading notification, which 
 
904
   must have happened when having a ERL_DE_PROC_LOADED entry, but that might 
 
905
   have been removed */
 
906
 
 
907
void erts_ddll_increment_port_count(DE_Handle *dh)
 
908
{
 
909
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
910
    dh->port_count++;
 
911
}
 
912
 
 
913
int erts_ddll_driver_ok(DE_Handle *dh) {
 
914
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
915
    return ((dh == NULL) || dh->status != ERL_DE_FORCE_UNLOAD);
 
916
}
 
917
 
 
918
void erts_ddll_decrement_port_count(DE_Handle *dh)
 
919
{
 
920
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
921
    dh->port_count--;
 
922
    if (dh->port_count == 0 && dh->status != ERL_DE_OK) {
 
923
        DE_ProcEntry **p = &(dh->procs);
 
924
        Eterm save_driver_name;
 
925
        do_unload_driver_entry(dh,&save_driver_name);
 
926
        while (*p != NULL) {
 
927
            DE_ProcEntry *q;
 
928
            if ((*p)->awaiting_status == ERL_DE_PROC_AWAIT_UNLOAD) {
 
929
                notify_proc((*p)->proc, 
 
930
                            make_internal_ref(&((*p)->heap)),
 
931
                            save_driver_name,am_DOWN,am_unloaded, 0);
 
932
                q = *p;
 
933
                *p = q->next;
 
934
                erts_free(ERTS_ALC_T_DDLL_PROCESS, (void *) q);
 
935
            } else {
 
936
                ASSERT(dh->status == ERL_DE_RELOAD);
 
937
                p = &((*p)->next);
 
938
            }
 
939
        }
 
940
 
 
941
        if (dh->status == ERL_DE_UNLOAD || dh->status == ERL_DE_FORCE_UNLOAD) {
 
942
            ASSERT(dh->full_path != NULL);
 
943
            erts_free(ERTS_ALC_T_DDLL_HANDLE, (void *) dh->full_path);
 
944
            erts_free(ERTS_ALC_T_DDLL_HANDLE, (void *) dh);
 
945
        } else { /* ERL_DE_RELOAD */
 
946
            int reload_res =
 
947
                reload_driver_entry(dh);
 
948
            p = &(dh->procs);
 
949
            while (*p != NULL) {
 
950
                DE_ProcEntry *q;
 
951
                if ((*p)->awaiting_status == ERL_DE_PROC_AWAIT_LOAD) {
 
952
                    if (reload_res == 0) {
 
953
                        notify_proc((*p)->proc, 
 
954
                                    make_internal_ref(&((*p)->heap)),
 
955
                                    save_driver_name, am_UP, am_loaded, 0);
 
956
                    } else {
 
957
                        notify_proc((*p)->proc, 
 
958
                                    make_internal_ref(&((*p)->heap)),
 
959
                                    save_driver_name, am_DOWN, am_load_failure, reload_res);
 
960
                    }
 
961
                    q = *p;
 
962
                    *p = q->next;
 
963
                    erts_free(ERTS_ALC_T_DDLL_PROCESS, (void *) q);
 
964
                } else {
 
965
                    if (reload_res != 0) {
 
966
                        DE_ProcEntry *q = *p;
 
967
                        *p = q->next;
 
968
                        erts_free(ERTS_ALC_T_DDLL_PROCESS, (void *) q);
 
969
                    } else {
 
970
                        p = &((*p)->next);
 
971
                    }
 
972
                }
 
973
            }
 
974
            if (reload_res != 0) {
 
975
                ASSERT(dh->full_path == NULL);
 
976
                erts_free(ERTS_ALC_T_DDLL_HANDLE, (void *) dh);
 
977
            }
 
978
        }
 
979
    }       
 
980
}    
 
981
 
 
982
 
 
983
char *erts_ddll_error(int code) {
 
984
    switch (code) {
 
985
    case ERL_DE_NO_ERROR:
 
986
        return "No error";
 
987
    case ERL_DE_LOAD_ERROR_NO_INIT:
 
988
        return "No driver init in dynamic library";
 
989
    case  ERL_DE_LOAD_ERROR_FAILED_INIT:
 
990
        return "Driver init failed";
 
991
    case ERL_DE_LOAD_ERROR_BAD_NAME:
 
992
        return "Bad driver name";
 
993
    case ERL_DE_LOAD_ERROR_NAME_TO_LONG:
 
994
        return "Driver name to long";
 
995
    case ERL_DE_ERROR_NO_DDLL_FUNCTIONALITY:
 
996
        return "DDLL functionality not available on this platform";
 
997
    case ERL_DE_ERROR_UNSPECIFIED:
 
998
        return "Unspecified dynamic library error";
 
999
    case ERL_DE_LOOKUP_ERROR_NOT_FOUND:
 
1000
        return "Symbol not found in dynamic library";
 
1001
    default:
 
1002
        return erts_sys_ddll_error(code);
 
1003
    }
 
1004
}
 
1005
 
 
1006
/*
 
1007
 * Utilities
 
1008
 */
 
1009
static Eterm notify_when_loaded(Process *p, Eterm name_term, char *name, Uint32 plocks)
 
1010
 
1011
    Eterm r = NIL;
 
1012
    Eterm immediate_tag = NIL;
 
1013
    Eterm immediate_type = NIL;
 
1014
    DE_List *de;
 
1015
 
 
1016
    ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN & plocks);
 
1017
#if DDLL_SMP 
 
1018
    if (erts_smp_io_trylock() == EBUSY) {
 
1019
        /* Unlock process locks, and acquire locks in lock order... */
 
1020
        erts_smp_proc_unlock(p, plocks);
 
1021
        erts_smp_io_lock();
 
1022
        erts_smp_proc_lock(p, plocks);
 
1023
    }
 
1024
#endif
 
1025
    if ((de = lookup_driver(name)) == NULL) {
 
1026
        immediate_tag = am_unloaded;
 
1027
        immediate_type = am_DOWN;
 
1028
        goto immediate;
 
1029
    }
 
1030
    if (de->de_hndl == NULL || de->de_hndl->status == ERL_DE_PERMANENT) {
 
1031
        immediate_tag = am_permanent;
 
1032
        immediate_type = am_UP;
 
1033
        goto immediate;
 
1034
    }   
 
1035
 
 
1036
    switch (de->de_hndl->status) {
 
1037
    case ERL_DE_OK:
 
1038
        immediate_tag = am_loaded;
 
1039
        immediate_type = am_UP;
 
1040
        goto immediate;
 
1041
    case ERL_DE_UNLOAD:
 
1042
    case ERL_DE_FORCE_UNLOAD:
 
1043
        immediate_tag = am_load_cancelled;
 
1044
        immediate_type = am_DOWN;
 
1045
        goto immediate;
 
1046
    case ERL_DE_RELOAD:
 
1047
        break;
 
1048
    default:
 
1049
        erl_exit(1,"Internal error, unknown state %u in dynamic driver.", de->de_hndl->status);
 
1050
    }
 
1051
    p->flags |= F_USING_DDLL;
 
1052
    r = add_monitor(p, de->de_hndl, ERL_DE_PROC_AWAIT_LOAD);
 
1053
#if DDLL_SMP
 
1054
    erts_smp_io_unlock();
 
1055
#endif
 
1056
    BIF_RET(r);
 
1057
 immediate:
 
1058
    r =  erts_make_ref(p);
 
1059
#if DDLL_SMP 
 
1060
    erts_smp_proc_unlock(p, plocks);
 
1061
#endif
 
1062
    notify_proc(p, r, name_term, immediate_type, immediate_tag, 0);
 
1063
#if DDLL_SMP
 
1064
    erts_smp_io_unlock();
 
1065
    erts_smp_proc_lock(p, plocks);
 
1066
#endif
 
1067
    BIF_RET(r);
 
1068
}
 
1069
 
 
1070
static Eterm notify_when_unloaded(Process *p, Eterm name_term, char *name, Uint32 plocks)
 
1071
 
1072
    Eterm r = NIL;
 
1073
    Eterm immediate_tag = NIL;
 
1074
    Eterm immediate_type = NIL;
 
1075
    DE_List *de;
 
1076
 
 
1077
    ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN & plocks);
 
1078
#if DDLL_SMP 
 
1079
    if (erts_smp_io_trylock() == EBUSY) {
 
1080
        /* Unlock process locks, and acquire locks in lock order... */
 
1081
        erts_smp_proc_unlock(p, plocks);
 
1082
        erts_smp_io_lock();
 
1083
        erts_smp_proc_lock(p, plocks);
 
1084
    }
 
1085
#endif
 
1086
    if ((de = lookup_driver(name)) == NULL) {
 
1087
        immediate_tag = am_unloaded;
 
1088
        immediate_type = am_DOWN;
 
1089
        goto immediate;
 
1090
    }
 
1091
    if (de->de_hndl == NULL || de->de_hndl->status == ERL_DE_PERMANENT) {
 
1092
        immediate_tag = am_permanent;
 
1093
        immediate_type = am_UP;
 
1094
        goto immediate;
 
1095
    }   
 
1096
 
 
1097
    p->flags |= F_USING_DDLL;
 
1098
    r = add_monitor(p, de->de_hndl, ERL_DE_PROC_AWAIT_UNLOAD);
 
1099
#if DDLL_SMP
 
1100
    erts_smp_io_unlock();
 
1101
#endif
 
1102
    BIF_RET(r);
 
1103
 immediate:
 
1104
    r =  erts_make_ref(p);
 
1105
#if DDLL_SMP 
 
1106
    erts_smp_proc_unlock(p, plocks);
 
1107
#endif
 
1108
    notify_proc(p, r, name_term, immediate_type, immediate_tag, 0);
 
1109
#if DDLL_SMP
 
1110
    erts_smp_io_unlock();
 
1111
    erts_smp_proc_lock(p, plocks);
 
1112
#endif
 
1113
    BIF_RET(r);
 
1114
}
 
1115
 
 
1116
static DE_ProcEntry *find_proc_entry(DE_Handle *dh, Process *proc, Uint status)
 
1117
{
 
1118
    DE_ProcEntry *p = dh->procs;
 
1119
 
 
1120
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
1121
 
 
1122
    while (p != NULL) {
 
1123
        if (p->proc == proc && p->awaiting_status == status) {
 
1124
            return p;
 
1125
        }
 
1126
        p = p->next;
 
1127
    }
 
1128
    return NULL;
 
1129
}
 
1130
 
 
1131
static void remove_proc_entry(DE_Handle *dh, DE_ProcEntry *pe)
 
1132
{
 
1133
    DE_ProcEntry **p = &(dh->procs);
 
1134
 
 
1135
    while (*p != NULL && *p != pe) {
 
1136
        p = &((*p)->next);
 
1137
    }
 
1138
    if ((*p) != NULL) {
 
1139
        *p = (*p)->next;
 
1140
    }
 
1141
}
 
1142
 
 
1143
static int num_procs(DE_Handle *dh, Uint status) {
 
1144
    DE_ProcEntry *p = dh->procs;
 
1145
    int i = 0;
 
1146
 
 
1147
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
1148
 
 
1149
    while (p != NULL) {
 
1150
        if (p->awaiting_status == status) {
 
1151
            ++i;
 
1152
        }
 
1153
        p = p->next;
 
1154
    }
 
1155
    return i;
 
1156
}
 
1157
/*
 
1158
static int num_entries(DE_Handle *dh, Process *proc, Uint status) {    
 
1159
    DE_ProcEntry *p = dh->procs;
 
1160
    int i = 0;
 
1161
 
 
1162
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
1163
 
 
1164
    while (p != NULL) {
 
1165
        if (p->awaiting_status == status && p->proc == proc) {
 
1166
            ++i;
 
1167
        }
 
1168
        p = p->next;
 
1169
    }
 
1170
    return i;
 
1171
}
 
1172
*/
 
1173
static void add_proc_loaded(DE_Handle *dh, Process *proc) 
 
1174
{
 
1175
    DE_ProcEntry *p;
 
1176
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
1177
    p = erts_alloc(ERTS_ALC_T_DDLL_PROCESS, sizeof(DE_ProcEntry));
 
1178
    p->proc = proc;
 
1179
    p->awaiting_status = ERL_DE_PROC_LOADED;
 
1180
    p->next = dh->procs;
 
1181
    dh->procs = p;
 
1182
}
 
1183
 
 
1184
static Eterm copy_ref(Eterm ref, Eterm *hp)
 
1185
{
 
1186
    RefThing *ptr = ref_thing_ptr(ref);
 
1187
    memcpy(hp, ptr, sizeof(RefThing));
 
1188
    return (make_internal_ref(hp));
 
1189
}
 
1190
 
 
1191
static void add_proc_waiting(DE_Handle *dh, Process *proc, 
 
1192
                             Uint status, Eterm ref) 
 
1193
{
 
1194
    DE_ProcEntry *p;
 
1195
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
1196
    p = erts_alloc(ERTS_ALC_T_DDLL_PROCESS, sizeof(DE_ProcEntry));
 
1197
    p->proc = proc;
 
1198
    p->awaiting_status = status;
 
1199
    copy_ref(ref, p->heap);
 
1200
    p->next = dh->procs;
 
1201
    dh->procs = p;
 
1202
}
 
1203
 
 
1204
static Eterm add_monitor(Process *p, DE_Handle *dh, Uint status)
 
1205
{
 
1206
    Eterm r;
 
1207
 
 
1208
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
1209
    r = erts_make_ref(p);
 
1210
    add_proc_waiting(dh, p, status, r);
 
1211
    return r;
 
1212
}
 
1213
    
 
1214
 
 
1215
static void set_driver_reloading(DE_Handle *dh, Process *proc, char *path, char *name, Uint flags)
 
1216
{
 
1217
    DE_ProcEntry *p;
 
1218
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
1219
    p = erts_alloc(ERTS_ALC_T_DDLL_PROCESS, sizeof(DE_ProcEntry));
 
1220
    p->proc = proc;
 
1221
    p->awaiting_status = ERL_DE_OK;
 
1222
    p->next = dh->procs;
 
1223
    dh->procs = p;
 
1224
    dh->status = ERL_DE_RELOAD;
 
1225
    dh->reload_full_path = erts_alloc(ERTS_ALC_T_DDLL_HANDLE, sys_strlen(path) + 1);
 
1226
    strcpy(dh->reload_full_path,path);
 
1227
    dh->reload_driver_name = erts_alloc(ERTS_ALC_T_DDLL_HANDLE, sys_strlen(name) + 1);
 
1228
    strcpy(dh->reload_driver_name,name);
 
1229
    dh->reload_flags = flags;
 
1230
}
 
1231
 
 
1232
static int do_load_driver_entry(DE_Handle *dh, char *path, char *name)
 
1233
{
 
1234
    void *init_handle;
 
1235
    int res;
 
1236
    ErlDrvEntry *dp;
 
1237
 
 
1238
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
1239
 
 
1240
    if ((res =  erts_sys_ddll_open(path, &(dh->handle))) != ERL_DE_NO_ERROR) {
 
1241
        return res;
 
1242
    }
 
1243
    
 
1244
    if ((res = erts_sys_ddll_load_driver_init(dh->handle, 
 
1245
                                              &init_handle)) != ERL_DE_NO_ERROR) {
 
1246
        erts_sys_ddll_close(dh->handle);
 
1247
        return ERL_DE_LOAD_ERROR_NO_INIT;
 
1248
    }
 
1249
    
 
1250
    dp = erts_sys_ddll_call_init(init_handle);
 
1251
    if (dp == NULL) {
 
1252
        erts_sys_ddll_close(dh->handle);
 
1253
        return ERL_DE_LOAD_ERROR_FAILED_INIT;
 
1254
    }
 
1255
    if (strcmp(name, dp->driver_name) != 0) {
 
1256
        erts_sys_ddll_close(dh->handle);
 
1257
        return ERL_DE_LOAD_ERROR_BAD_NAME;
 
1258
    }
 
1259
    dh->port_count = 0;
 
1260
    dh->full_path = erts_alloc(ERTS_ALC_T_DDLL_HANDLE, sys_strlen(path) + 1);
 
1261
    sys_strcpy(dh->full_path, path);
 
1262
    dh->flags = 0;
 
1263
    dh->status = ERL_DE_OK;
 
1264
    dp->handle = dh;
 
1265
 
 
1266
    add_driver_entry(dp); /* io.c */
 
1267
 
 
1268
    return ERL_DE_NO_ERROR;
 
1269
}
 
1270
 
 
1271
static int do_unload_driver_entry(DE_Handle *dh, Eterm *save_name)
 
1272
{
 
1273
    DE_List **p = &driver_list;
 
1274
    DE_List *q;
 
1275
    int i;
 
1276
 
 
1277
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
1278
 
 
1279
    /* XXX:PaN only in DEBUG code? */
 
1280
    for (i = 0; i < erts_max_ports; i++) {
 
1281
        if (erts_port[i].status != FREE &&
 
1282
            !(erts_port[i].status & EXITING) &&
 
1283
            erts_port[i].drv_ptr->handle == dh) {
 
1284
            erl_exit(1,"Internal error: Port %d holding dynamic "
 
1285
                     "driver without reference count",i);
 
1286
        }
 
1287
    }
 
1288
 
 
1289
    while (*p != NULL) {
 
1290
        if ((*p)->de_hndl == dh) {
 
1291
                
 
1292
            q = *p;
 
1293
            *p = (*p)->next;
 
1294
            if (save_name != NULL) {
 
1295
                *save_name = mkatom(q->drv->driver_name);
 
1296
            } 
 
1297
            /* XXX:PaN Future locking problems? */
 
1298
            if (q->drv->finish) {
 
1299
                (*(q->drv->finish))();
 
1300
            }
 
1301
            erts_sys_ddll_close(dh->handle);
 
1302
            erts_free(ERTS_ALC_T_DRV_ENTRY_LIST, (void *) q);
 
1303
            return 1;
 
1304
        }
 
1305
        p = &(*p)->next;
 
1306
    }
 
1307
    return 0;
 
1308
}
 
1309
 
 
1310
static int load_driver_entry(DE_Handle **dhp, char *path, char *name)
 
1311
{
 
1312
    int res;
 
1313
    DE_Handle *dh = erts_alloc(ERTS_ALC_T_DDLL_HANDLE, sizeof(DE_Handle));
 
1314
    dh->handle = NULL;
 
1315
    dh->procs = NULL;
 
1316
    dh->port_count = 0;
 
1317
    dh->status = -1;
 
1318
    dh->reload_full_path = NULL;
 
1319
    dh->reload_driver_name = NULL;
 
1320
    dh->reload_flags = 0;
 
1321
    dh->full_path = NULL;
 
1322
    dh->flags = 0;
 
1323
 
 
1324
    if ((res = do_load_driver_entry(dh, path, name)) != ERL_DE_NO_ERROR) {
 
1325
        erts_free(ERTS_ALC_T_DDLL_HANDLE, (void *) dh);
 
1326
        dh = NULL;
 
1327
    }
 
1328
    *dhp = dh;
 
1329
    return res;
 
1330
}
 
1331
 
 
1332
static void unload_driver_entry(DE_Handle *dh)
 
1333
{
 
1334
    do_unload_driver_entry(dh, NULL);
 
1335
    if (dh->full_path != NULL) {
 
1336
        erts_free(ERTS_ALC_T_DDLL_HANDLE, (void *) dh->full_path);
 
1337
    }
 
1338
    erts_free(ERTS_ALC_T_DDLL_HANDLE, (void *) dh);
 
1339
}
 
1340
 
 
1341
static int reload_driver_entry(DE_Handle *dh)
 
1342
{
 
1343
    char *path = dh->reload_full_path;
 
1344
    char *name = dh->reload_driver_name;
 
1345
    int loadres;
 
1346
    Uint flags = dh->reload_flags;
 
1347
 
 
1348
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
1349
 
 
1350
    dh->reload_full_path = NULL;
 
1351
    dh->reload_driver_name = NULL;
 
1352
 
 
1353
    ASSERT(dh->port_count == 0);
 
1354
    ASSERT(dh->full_path != NULL);
 
1355
    erts_free(ERTS_ALC_T_DDLL_HANDLE, (void *) dh->full_path);
 
1356
    dh->full_path = NULL;
 
1357
 
 
1358
    loadres = do_load_driver_entry(dh, path, name);
 
1359
    erts_free(ERTS_ALC_T_DDLL_HANDLE, (void *) path);
 
1360
    erts_free(ERTS_ALC_T_DDLL_HANDLE, (void *) name);
 
1361
    if (loadres == ERL_DE_NO_ERROR) {
 
1362
        dh->status = ERL_DE_OK;
 
1363
        dh->flags = flags;
 
1364
    }
 
1365
    return loadres;
 
1366
}
 
1367
 
 
1368
/*
 
1369
 * Notification {tag = atom(), ref = ref(), driver_name = atom()} or
 
1370
 *              {'$DDLL_load_failure', ref = ref(), driver_name = atom(), 
 
1371
 *               error_term = atom() | {system_error, int()}}
 
1372
 */
 
1373
   
 
1374
static void notify_proc(Process *proc, Eterm ref, Eterm driver_name, Eterm type, 
 
1375
                        Eterm tag, int errcode)
 
1376
{
 
1377
    Eterm mess;
 
1378
    Eterm r;
 
1379
    Eterm *hp;
 
1380
    ErlHeapFragment *bp;
 
1381
    ErlOffHeap *ohp;
 
1382
    Uint32 rp_locks = ERTS_PROC_LOCKS_MSG_SEND;
 
1383
    ERTS_SMP_CHK_NO_PROC_LOCKS;
 
1384
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
1385
    erts_smp_proc_lock(proc, rp_locks);
 
1386
    if (errcode != 0) {
 
1387
        int need = load_error_need(errcode);
 
1388
        Eterm e;
 
1389
        hp = erts_alloc_message_heap(6 /* tuple */ + 3 /* Error tuple */ + 
 
1390
                                     REF_THING_SIZE + need, &bp, &ohp, 
 
1391
                                     proc, &rp_locks);
 
1392
        r = copy_ref(ref,hp);
 
1393
        hp += REF_THING_SIZE;
 
1394
        e = build_load_error_hp(hp, errcode);
 
1395
        hp += need;
 
1396
        mess = TUPLE2(hp,tag,e);
 
1397
        hp += 3;
 
1398
        mess = TUPLE5(hp,type,r,am_driver,driver_name,mess);
 
1399
    } else {    
 
1400
        hp = erts_alloc_message_heap(6 /* tuple */ + REF_THING_SIZE, &bp, &ohp, proc, &rp_locks);
 
1401
        r = copy_ref(ref,hp);
 
1402
        hp += REF_THING_SIZE;
 
1403
        mess = TUPLE5(hp,type,r,am_driver,driver_name,tag);
 
1404
    }
 
1405
    erts_queue_message(proc, rp_locks, bp, mess, am_undefined);
 
1406
    erts_smp_proc_unlock(proc, rp_locks);
 
1407
    ERTS_SMP_CHK_NO_PROC_LOCKS;
 
1408
}
 
1409
 
 
1410
static void notify_all(DE_Handle *dh, char *name, Uint awaiting, Eterm type, Eterm tag)
 
1411
{
 
1412
    DE_ProcEntry **p;
 
1413
 
 
1414
    p = &(dh->procs);
 
1415
    while (*p != NULL) {
 
1416
        if ((*p)->awaiting_status == awaiting) {
 
1417
            DE_ProcEntry *pe;
 
1418
            pe = *p;
 
1419
            *p = pe->next;
 
1420
            notify_proc(pe->proc, make_internal_ref(&(pe->heap)), mkatom(name), type, tag, 0);
 
1421
            erts_free(ERTS_ALC_T_DDLL_PROCESS, (void *) pe);
 
1422
        } else {
 
1423
            p = &((*p)->next);
 
1424
        }
 
1425
    }
 
1426
}
 
1427
 
 
1428
 
 
1429
 
 
1430
typedef struct errcode_entry {
 
1431
    char *atm;
 
1432
    int code;
 
1433
} ErrcodeEntry;
 
1434
 
 
1435
static ErrcodeEntry errcode_tab[] = {
 
1436
    {"no_error", ERL_DE_NO_ERROR},
 
1437
    {"no_driver_init", ERL_DE_LOAD_ERROR_NO_INIT},
 
1438
    {"driver_init_failed", ERL_DE_LOAD_ERROR_FAILED_INIT},
 
1439
    {"bad_driver_name", ERL_DE_LOAD_ERROR_BAD_NAME},
 
1440
    {"driver_name_to_long", ERL_DE_LOAD_ERROR_NAME_TO_LONG},
 
1441
    {"no_ddll_available",  ERL_DE_ERROR_NO_DDLL_FUNCTIONALITY},
 
1442
    {"unspecified_error", ERL_DE_ERROR_UNSPECIFIED},
 
1443
    {"symbol_not_found", ERL_DE_LOOKUP_ERROR_NOT_FOUND},
 
1444
    {NULL,0}
 
1445
};
 
1446
 
 
1447
static int errdesc_to_code(Eterm errdesc, int *code /* out */)
 
1448
{
 
1449
    int i;
 
1450
    if (is_atom(errdesc)) {
 
1451
        Atom *ap = atom_tab(atom_val(errdesc)); 
 
1452
        for (i = 0; errcode_tab[i].atm != NULL; ++i) {
 
1453
            int len = sys_strlen(errcode_tab[i].atm);
 
1454
            if (len == ap->len && 
 
1455
                !sys_strncmp(errcode_tab[i].atm,(char *) ap->name,len)) {
 
1456
                *code = errcode_tab[i].code;
 
1457
                return 0;
 
1458
            }
 
1459
        }
 
1460
        return -1;
 
1461
    } else if (is_tuple(errdesc)) {
 
1462
        Eterm *tp = tuple_val(errdesc);
 
1463
        if (*tp != make_arityval(2) || tp[1] != am_open_error || is_not_small(tp[2])) {
 
1464
            return -1;
 
1465
        }
 
1466
        *code = signed_val(tp[2]);
 
1467
        return 0;
 
1468
    }
 
1469
    return -1;
 
1470
}
 
1471
 
 
1472
static Eterm build_load_error(Process *p, int code)
 
1473
{
 
1474
    int need = load_error_need(code);
 
1475
    Eterm *hp = NULL;
 
1476
    ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(p));
 
1477
    if (need) {
 
1478
        hp = HAlloc(p,need);
 
1479
    }
 
1480
    return build_load_error_hp(hp,code);
 
1481
}
 
1482
    
 
1483
static int load_error_need(int code)
 
1484
{
 
1485
    ErrcodeEntry *ee = errcode_tab;
 
1486
    while (ee->atm != NULL) {
 
1487
        if (ee->code == code) {
 
1488
            return 0;
 
1489
        }
 
1490
        ++ee;
 
1491
    }
 
1492
    return 3;
 
1493
}
 
1494
 
 
1495
static Eterm build_load_error_hp(Eterm *hp, int code)
 
1496
{
 
1497
    ErrcodeEntry *ee = errcode_tab;
 
1498
    while (ee->atm != NULL) {
 
1499
        if (ee->code == code) {
 
1500
            return mkatom(ee->atm);
 
1501
        }
 
1502
        ++ee;
 
1503
    }
 
1504
    return TUPLE2(hp,am_open_error, make_small(code));
 
1505
}
 
1506
    
 
1507
 
 
1508
 
 
1509
static Eterm mkatom(char *str)
 
1510
{
 
1511
    return am_atom_put(str, sys_strlen(str));
 
1512
}
 
1513
 
 
1514
static char *pick_list_or_atom(Eterm name_term)
 
1515
 
1516
    char *name = NULL;
 
1517
    int name_len;
 
1518
    if (is_atom(name_term)) {
 
1519
        Atom *ap = atom_tab(atom_val(name_term));
 
1520
        if (ap->len == 0) {
 
1521
            /* If io_lists with zero length is not allowed, 
 
1522
               then the empty atom shouldn't */
 
1523
            goto error;
 
1524
        }
 
1525
        name = erts_alloc(ERTS_ALC_T_DDLL_TMP_BUF, ap->len + 1);
 
1526
        memcpy(name,ap->name,ap->len);
 
1527
        name[ap->len] = '\0';
 
1528
    } else {
 
1529
        name_len = io_list_len(name_term);
 
1530
        if (name_len <= 0) {
 
1531
            goto error;
 
1532
        }
 
1533
        name = erts_alloc(ERTS_ALC_T_DDLL_TMP_BUF, name_len + 1);
 
1534
        if (io_list_to_buf(name_term, name, name_len) != 0) {
 
1535
            goto error;
 
1536
        }
 
1537
        name[name_len] = '\0';
 
1538
    }
 
1539
    return name;
 
1540
 error:
 
1541
    if (name != NULL) {
 
1542
        erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
 
1543
    }
 
1544
    return NULL;
 
1545
}
 
1546
 
 
1547
static int build_proc_info(DE_Handle *dh, ProcEntryInfo **out_pei, Uint filter)
 
1548
{
 
1549
    ProcEntryInfo *pei = NULL;
 
1550
    int num_pei = 0;
 
1551
    int num_pei_allocated = 0;
 
1552
    int i;
 
1553
    DE_ProcEntry *pe;
 
1554
 
 
1555
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
1556
 
 
1557
    for (pe = dh->procs; pe != NULL; pe = pe->next) {
 
1558
        Eterm id = pe->proc->id;
 
1559
        Uint stat = pe->awaiting_status;
 
1560
        if (stat != filter) {
 
1561
            continue;
 
1562
        }
 
1563
        for (i = 0; i < num_pei; ++i) {
 
1564
            if (pei[i].pid == id && pei[i].status == stat) {
 
1565
                break;
 
1566
            }
 
1567
        }
 
1568
        if (i < num_pei) {
 
1569
            pei[i].count++;
 
1570
        } else {
 
1571
            if (num_pei >= num_pei_allocated) {
 
1572
                pei = (pei == NULL) 
 
1573
                    ? erts_alloc(ERTS_ALC_T_DDLL_TMP_BUF, 
 
1574
                                 sizeof(ProcEntryInfo) * (num_pei_allocated = 10))
 
1575
                    : erts_realloc(ERTS_ALC_T_DDLL_TMP_BUF, pei,
 
1576
                                   sizeof(ProcEntryInfo) * (num_pei_allocated += 10));
 
1577
            }
 
1578
            pei[num_pei].pid = id;
 
1579
            pei[num_pei].proc = pe->proc;
 
1580
            pei[num_pei].status = stat;
 
1581
            pei[num_pei].count = 1;
 
1582
            ++num_pei;
 
1583
        }
 
1584
    }
 
1585
    *out_pei = pei;
 
1586
    return num_pei;
 
1587
}
 
1588
            
 
1589
    
 
1590
 
 
1591
static DE_List *lookup_driver(char *name)
 
1592
{
 
1593
    DE_List *de;
 
1594
    ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
 
1595
    for (de = driver_list; de != NULL && strcmp(de->drv->driver_name,name); de = de->next)
 
1596
        ;
 
1597
    return de;
 
1598
}
 
1599