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/.
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
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.''
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
36
#include "erl_process.h"
38
#include "erl_driver.h"
42
#include "erl_version.h"
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);
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()}
97
BIF_RETTYPE erl_ddll_try_load_3(Process *p, Eterm path_term,
98
Eterm name_term, Eterm options)
104
int have_proc_lock = 1;
109
Eterm soft_error_term = NIL;
117
for(l = options; is_list(l); l = CDR(list_val(l))) {
118
Eterm opt = CAR(list_val(l));
120
if (is_not_tuple(opt)) {
124
if (*tp != make_arityval(2) || is_not_atom(tp[1])) {
128
case am_driver_options:
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;
139
if (is_not_nil(ll)) {
145
if (tp[2] != am_pending_driver && tp[2] != am_pending ) {
159
if ((name = pick_list_or_atom(name_term)) == NULL) {
163
path_len = io_list_len(path_term);
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) {
172
while (path_len > 0 && (path[path_len-1] == '\\' || path[path_len-1] == '/')) {
175
path[path_len++] = '/';
176
/*path[path_len] = '\0';*/
177
sys_strcpy(path+path_len,name);
180
erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
185
if ((de = lookup_driver(name)) != NULL) {
186
if (de->de_hndl == NULL) {
188
soft_error_term = am_linked_in_driver;
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;
199
add_proc_loaded(dh,p);
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;
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;
222
if ((res = load_driver_entry(&dh, path, name)) != ERL_DE_NO_ERROR) {
224
/* Need process lock for build_load_error */
225
erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
228
soft_error_term = build_load_error(p, res);
232
add_proc_loaded(dh,p);
234
ok_term = mkatom("loaded");
237
ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
239
if (!have_proc_lock) {
240
erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
243
p->flags |= F_USING_DDLL;
245
Eterm mref = add_monitor(p, dh, ERL_DE_PROC_AWAIT_LOAD);
247
t = TUPLE3(hp, am_ok, ok_term, mref);
250
t = TUPLE2(hp, am_ok, ok_term);
253
erts_smp_io_unlock();
255
erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) path);
256
erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
259
ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
261
erts_smp_io_unlock();
262
if (!have_proc_lock) {
263
erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
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);
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));
275
erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) path);
278
erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
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
292
If the driver is loaded and free to unload (you're the last holding it)
294
If it's not loaded or not loaded by you
295
{error, not_loaded} or {error, not_loaded_by_you}
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}
305
Eterm erl_ddll_try_unload_2(Process *p, Eterm name_term, Eterm options)
309
Eterm soft_error_term = NIL;
319
for(l = options; is_list(l); l = CDR(list_val(l))) {
320
Eterm opt = CAR(list_val(l));
322
if (is_not_tuple(opt)) {
323
if (opt == am_kill_ports) {
331
if (*tp != make_arityval(2) || tp[1] != am_monitor) {
334
if (tp[2] == am_pending_driver) {
336
} else if (tp[2] == am_pending) {
346
if ((name = pick_list_or_atom(name_term)) == NULL) {
351
erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
355
if ((de = lookup_driver(name)) == NULL) {
356
soft_error_term = am_not_loaded;
360
if (de->de_hndl == NULL) {
361
soft_error_term = am_linked_in_driver;
363
} else if (de->de_hndl->status == ERL_DE_PERMANENT) {
364
soft_error_term = am_permanent;
368
if (dh->flags & ERL_DE_FL_KILL_PORTS) {
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;
377
remove_proc_entry(dh, pe);
378
erts_free(ERTS_ALC_T_DDLL_PROCESS, pe);
380
if (num_procs(dh, ERL_DE_PROC_LOADED) > 0) {
381
ok_term = mkatom("pending_process");
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;
395
dh->status = ERL_DE_UNLOAD;
396
ok_term = am_pending_driver;
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);
408
ok_term = mkatom("unloaded");
410
ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
412
erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
414
p->flags |= F_USING_DDLL;
416
Eterm mref = add_monitor(p, dh, ERL_DE_PROC_AWAIT_UNLOAD);
418
t = TUPLE3(hp, am_ok, ok_term, mref);
421
t = TUPLE2(hp, am_ok, ok_term);
423
if (kill_ports > 1) {
425
int c = dh->port_count;
427
erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
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 */
435
driver_failure_atom(j, "driver_unloaded");
439
erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
443
erts_smp_io_unlock();
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 */
452
ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
454
erts_smp_io_unlock();
455
erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
457
erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
459
t = TUPLE2(hp, am_error, soft_error_term);
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));
466
erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
473
* A shadow of the "real" demonitor BIF
475
BIF_RETTYPE erl_ddll_demonitor_1(Process *p, Eterm ref)
477
if (is_not_internal_ref(ref)) {
478
BIF_ERROR(p, BADARG);
480
if (p->flags & F_USING_DDLL) {
481
erts_ddll_remove_monitor(p, ref, ERTS_PROC_LOCK_MAIN);
487
* A shadow of the "real" monitor BIF
489
BIF_RETTYPE erl_ddll_monitor_2(Process *p, Eterm dr, Eterm what)
491
if (dr != am_driver) {
494
return erts_ddll_monitor_driver(p, what, ERTS_PROC_LOCK_MAIN);
498
* Return list of loaded drivers {ok,[string()]}
500
Eterm erl_ddll_loaded_drivers_0(Process *p)
507
if (erts_smp_io_trylock() == EBUSY) {
508
erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
510
erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
513
for (de = driver_list; de != NULL; de = de->next) {
514
need += sys_strlen(de->drv->driver_name)*2+2;
517
for (de = driver_list; de != NULL; de = de->next) {
519
l = buf_to_intlist(&hp, de->drv->driver_name, sys_strlen(de->drv->driver_name), NIL);
520
res = CONS(hp,l,res);
523
res = TUPLE2(hp,am_ok,res);
526
erts_smp_io_unlock();
532
* More detailed info about loaded drivers:
533
* item is processes, driver_options, port_count, linked_in_driver,
534
* permanent, awaiting_load, awaiting_unload
536
Eterm erl_ddll_info_2(Process *p, Eterm name_term, Eterm item)
541
ProcEntryInfo *pei = NULL;
547
int have_io_lock = 0;
550
if ((name = pick_list_or_atom(name_term)) == NULL) {
554
if (!is_atom(item)) {
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);
563
erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
567
if ((de = lookup_driver(name)) == NULL) {
573
filter = ERL_DE_PROC_LOADED;
575
case am_driver_options:
576
if (de->de_hndl == NULL) {
577
res = am_linked_in_driver;
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) {
584
res = CONS(myhp,am_kill_ports,NIL);
591
if (de->de_hndl == NULL) {
592
res = am_linked_in_driver;
593
} else if (de->de_hndl->status == ERL_DE_PERMANENT) {
596
res = make_small(de->de_hndl->port_count);
599
case am_linked_in_driver:
600
if (de->de_hndl == NULL){
607
if (de->de_hndl != NULL && de->de_hndl->status == ERL_DE_PERMANENT) {
613
case am_awaiting_load:
614
filter = ERL_DE_PROC_AWAIT_LOAD;
616
case am_awaiting_unload:
617
filter = ERL_DE_PROC_AWAIT_UNLOAD;
623
if (de->de_hndl == NULL) {
624
res = am_linked_in_driver;
626
} else if (de->de_hndl->status == ERL_DE_PERMANENT) {
630
num_pei = build_proc_info(de->de_hndl, &pei, filter);
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));
638
res = CONS(hp,tpl,res);
643
erts_smp_io_unlock();
645
erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
649
erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
653
erts_smp_io_unlock();
660
* Backend for erl_ddll:format_error, handles all "soft" errors returned by builtins,
661
* possibly by calling the system specific error handler
663
Eterm erl_ddll_format_error_int_1(Process *p, Eterm code_term)
665
char *errstring = NULL;
671
/* These errors can only appear in the erlang interface, not in the interface provided
674
case am_inconsistent:
675
errstring = "Driver name and/or driver options are inconsistent with "
676
"currently loaded driver";
678
case am_linked_in_driver:
679
errstring = "Driver is statically linked and "
680
"cannot be loaded/unloaded";
683
errstring = "DDLL driver is permanent an can not be unloaded/loaded";
686
errstring = "DDLL driver is not loaded";
688
case am_not_loaded_by_this_process:
689
errstring = "DDLL driver was not loaded by this process";
692
errstring = "DDLL load not pending for this driver name";
694
case am_already_loaded:
695
errstring = "DDLL driver is already loaded successfully";
698
errstring = "Driver is unloading";
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) {
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);
711
erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
714
errstring = erts_ddll_error(errint);
716
erts_smp_io_unlock();
720
if (errstring == NULL) {
723
len = sys_strlen(errstring);
724
hp = HAlloc(p, 2 * len);
725
ret = buf_to_intlist(&hp, errstring, len, NIL);
731
void erts_ddll_init(void)
736
/* Return value as a bif, called by erlang:monitor */
737
Eterm erts_ddll_monitor_driver(Process *p, Eterm description, Uint32 plocks)
743
if (is_not_tuple(description)) {
746
tp = tuple_val(description);
747
if (*tp != make_arityval(2)) {
750
if ((name = pick_list_or_atom(tp[1])) == NULL) {
755
ERTS_BIF_PREP_RET(ret, notify_when_loaded(p,tp[1],name,plocks));
758
ERTS_BIF_PREP_RET(ret, notify_when_unloaded(p,tp[1],name,plocks));
761
ERTS_BIF_PREP_ERROR(ret,p,BADARG);
765
erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
769
void erts_ddll_remove_monitor(Process *p, Eterm ref, Uint32 plocks)
772
erts_smp_proc_unlock(p, plocks);
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;
785
erts_free(ERTS_ALC_T_DDLL_PROCESS, (void *) r);
794
erts_smp_io_unlock();
795
erts_smp_proc_lock(p, plocks);
799
* Called from erl_process.c, Need to take the io_lock.
801
void erts_ddll_proc_dead(Process *p, Uint32 plocks)
804
erts_smp_proc_unlock(p, plocks);
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);
812
while ((*pe) != NULL) {
813
if ((*pe)->proc == p) {
814
DE_ProcEntry *r = *pe;
816
erts_free(ERTS_ALC_T_DDLL_PROCESS, (void *) r);
818
if ((*pe)->awaiting_status == ERL_DE_PROC_LOADED) {
824
/* Do we have anyone holding the driver? */
825
if (!left && ((*de)->de_hndl->port_count == 0)) {
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);
832
if (dh->reload_driver_name != NULL) {
833
erts_free(ERTS_ALC_T_DDLL_HANDLE,dh->reload_driver_name);
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);
845
if (q->drv->finish) {
846
(*(q->drv->finish))();
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);
854
if (!left && ((*de)->de_hndl->port_count > 0)) {
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
866
driver_failure_atom(j, "driver_unloaded");
870
(*de)->de_hndl->status = ERL_DE_UNLOAD;
879
erts_smp_io_unlock();
880
erts_smp_proc_lock(p, plocks);
882
void erts_ddll_lock_driver(DE_Handle *dh, char *name)
886
ERL_DE_PROC_AWAIT_LOAD, am_UP, am_permanent);
888
ERL_DE_PROC_AWAIT_UNLOAD, am_UP, am_permanent);
894
erts_free(ERTS_ALC_T_DDLL_PROCESS, (void *) q);
896
dh->status = ERL_DE_PERMANENT;
900
ERL_DE_PROC_AWAIT_UNLOAD -> Awaiting actual unloading, can be anyone
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
907
void erts_ddll_increment_port_count(DE_Handle *dh)
909
ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
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);
918
void erts_ddll_decrement_port_count(DE_Handle *dh)
920
ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
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);
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);
934
erts_free(ERTS_ALC_T_DDLL_PROCESS, (void *) q);
936
ASSERT(dh->status == ERL_DE_RELOAD);
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 */
947
reload_driver_entry(dh);
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);
957
notify_proc((*p)->proc,
958
make_internal_ref(&((*p)->heap)),
959
save_driver_name, am_DOWN, am_load_failure, reload_res);
963
erts_free(ERTS_ALC_T_DDLL_PROCESS, (void *) q);
965
if (reload_res != 0) {
966
DE_ProcEntry *q = *p;
968
erts_free(ERTS_ALC_T_DDLL_PROCESS, (void *) q);
974
if (reload_res != 0) {
975
ASSERT(dh->full_path == NULL);
976
erts_free(ERTS_ALC_T_DDLL_HANDLE, (void *) dh);
983
char *erts_ddll_error(int code) {
985
case ERL_DE_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";
1002
return erts_sys_ddll_error(code);
1009
static Eterm notify_when_loaded(Process *p, Eterm name_term, char *name, Uint32 plocks)
1012
Eterm immediate_tag = NIL;
1013
Eterm immediate_type = NIL;
1016
ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN & plocks);
1018
if (erts_smp_io_trylock() == EBUSY) {
1019
/* Unlock process locks, and acquire locks in lock order... */
1020
erts_smp_proc_unlock(p, plocks);
1022
erts_smp_proc_lock(p, plocks);
1025
if ((de = lookup_driver(name)) == NULL) {
1026
immediate_tag = am_unloaded;
1027
immediate_type = am_DOWN;
1030
if (de->de_hndl == NULL || de->de_hndl->status == ERL_DE_PERMANENT) {
1031
immediate_tag = am_permanent;
1032
immediate_type = am_UP;
1036
switch (de->de_hndl->status) {
1038
immediate_tag = am_loaded;
1039
immediate_type = am_UP;
1042
case ERL_DE_FORCE_UNLOAD:
1043
immediate_tag = am_load_cancelled;
1044
immediate_type = am_DOWN;
1049
erl_exit(1,"Internal error, unknown state %u in dynamic driver.", de->de_hndl->status);
1051
p->flags |= F_USING_DDLL;
1052
r = add_monitor(p, de->de_hndl, ERL_DE_PROC_AWAIT_LOAD);
1054
erts_smp_io_unlock();
1058
r = erts_make_ref(p);
1060
erts_smp_proc_unlock(p, plocks);
1062
notify_proc(p, r, name_term, immediate_type, immediate_tag, 0);
1064
erts_smp_io_unlock();
1065
erts_smp_proc_lock(p, plocks);
1070
static Eterm notify_when_unloaded(Process *p, Eterm name_term, char *name, Uint32 plocks)
1073
Eterm immediate_tag = NIL;
1074
Eterm immediate_type = NIL;
1077
ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN & plocks);
1079
if (erts_smp_io_trylock() == EBUSY) {
1080
/* Unlock process locks, and acquire locks in lock order... */
1081
erts_smp_proc_unlock(p, plocks);
1083
erts_smp_proc_lock(p, plocks);
1086
if ((de = lookup_driver(name)) == NULL) {
1087
immediate_tag = am_unloaded;
1088
immediate_type = am_DOWN;
1091
if (de->de_hndl == NULL || de->de_hndl->status == ERL_DE_PERMANENT) {
1092
immediate_tag = am_permanent;
1093
immediate_type = am_UP;
1097
p->flags |= F_USING_DDLL;
1098
r = add_monitor(p, de->de_hndl, ERL_DE_PROC_AWAIT_UNLOAD);
1100
erts_smp_io_unlock();
1104
r = erts_make_ref(p);
1106
erts_smp_proc_unlock(p, plocks);
1108
notify_proc(p, r, name_term, immediate_type, immediate_tag, 0);
1110
erts_smp_io_unlock();
1111
erts_smp_proc_lock(p, plocks);
1116
static DE_ProcEntry *find_proc_entry(DE_Handle *dh, Process *proc, Uint status)
1118
DE_ProcEntry *p = dh->procs;
1120
ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
1123
if (p->proc == proc && p->awaiting_status == status) {
1131
static void remove_proc_entry(DE_Handle *dh, DE_ProcEntry *pe)
1133
DE_ProcEntry **p = &(dh->procs);
1135
while (*p != NULL && *p != pe) {
1143
static int num_procs(DE_Handle *dh, Uint status) {
1144
DE_ProcEntry *p = dh->procs;
1147
ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
1150
if (p->awaiting_status == status) {
1158
static int num_entries(DE_Handle *dh, Process *proc, Uint status) {
1159
DE_ProcEntry *p = dh->procs;
1162
ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
1165
if (p->awaiting_status == status && p->proc == proc) {
1173
static void add_proc_loaded(DE_Handle *dh, Process *proc)
1176
ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
1177
p = erts_alloc(ERTS_ALC_T_DDLL_PROCESS, sizeof(DE_ProcEntry));
1179
p->awaiting_status = ERL_DE_PROC_LOADED;
1180
p->next = dh->procs;
1184
static Eterm copy_ref(Eterm ref, Eterm *hp)
1186
RefThing *ptr = ref_thing_ptr(ref);
1187
memcpy(hp, ptr, sizeof(RefThing));
1188
return (make_internal_ref(hp));
1191
static void add_proc_waiting(DE_Handle *dh, Process *proc,
1192
Uint status, Eterm ref)
1195
ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
1196
p = erts_alloc(ERTS_ALC_T_DDLL_PROCESS, sizeof(DE_ProcEntry));
1198
p->awaiting_status = status;
1199
copy_ref(ref, p->heap);
1200
p->next = dh->procs;
1204
static Eterm add_monitor(Process *p, DE_Handle *dh, Uint status)
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);
1215
static void set_driver_reloading(DE_Handle *dh, Process *proc, char *path, char *name, Uint flags)
1218
ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
1219
p = erts_alloc(ERTS_ALC_T_DDLL_PROCESS, sizeof(DE_ProcEntry));
1221
p->awaiting_status = ERL_DE_OK;
1222
p->next = dh->procs;
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;
1232
static int do_load_driver_entry(DE_Handle *dh, char *path, char *name)
1238
ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
1240
if ((res = erts_sys_ddll_open(path, &(dh->handle))) != ERL_DE_NO_ERROR) {
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;
1250
dp = erts_sys_ddll_call_init(init_handle);
1252
erts_sys_ddll_close(dh->handle);
1253
return ERL_DE_LOAD_ERROR_FAILED_INIT;
1255
if (strcmp(name, dp->driver_name) != 0) {
1256
erts_sys_ddll_close(dh->handle);
1257
return ERL_DE_LOAD_ERROR_BAD_NAME;
1260
dh->full_path = erts_alloc(ERTS_ALC_T_DDLL_HANDLE, sys_strlen(path) + 1);
1261
sys_strcpy(dh->full_path, path);
1263
dh->status = ERL_DE_OK;
1266
add_driver_entry(dp); /* io.c */
1268
return ERL_DE_NO_ERROR;
1271
static int do_unload_driver_entry(DE_Handle *dh, Eterm *save_name)
1273
DE_List **p = &driver_list;
1277
ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
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);
1289
while (*p != NULL) {
1290
if ((*p)->de_hndl == dh) {
1294
if (save_name != NULL) {
1295
*save_name = mkatom(q->drv->driver_name);
1297
/* XXX:PaN Future locking problems? */
1298
if (q->drv->finish) {
1299
(*(q->drv->finish))();
1301
erts_sys_ddll_close(dh->handle);
1302
erts_free(ERTS_ALC_T_DRV_ENTRY_LIST, (void *) q);
1310
static int load_driver_entry(DE_Handle **dhp, char *path, char *name)
1313
DE_Handle *dh = erts_alloc(ERTS_ALC_T_DDLL_HANDLE, sizeof(DE_Handle));
1318
dh->reload_full_path = NULL;
1319
dh->reload_driver_name = NULL;
1320
dh->reload_flags = 0;
1321
dh->full_path = NULL;
1324
if ((res = do_load_driver_entry(dh, path, name)) != ERL_DE_NO_ERROR) {
1325
erts_free(ERTS_ALC_T_DDLL_HANDLE, (void *) dh);
1332
static void unload_driver_entry(DE_Handle *dh)
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);
1338
erts_free(ERTS_ALC_T_DDLL_HANDLE, (void *) dh);
1341
static int reload_driver_entry(DE_Handle *dh)
1343
char *path = dh->reload_full_path;
1344
char *name = dh->reload_driver_name;
1346
Uint flags = dh->reload_flags;
1348
ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
1350
dh->reload_full_path = NULL;
1351
dh->reload_driver_name = NULL;
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;
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;
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()}}
1374
static void notify_proc(Process *proc, Eterm ref, Eterm driver_name, Eterm type,
1375
Eterm tag, int errcode)
1380
ErlHeapFragment *bp;
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);
1387
int need = load_error_need(errcode);
1389
hp = erts_alloc_message_heap(6 /* tuple */ + 3 /* Error tuple */ +
1390
REF_THING_SIZE + need, &bp, &ohp,
1392
r = copy_ref(ref,hp);
1393
hp += REF_THING_SIZE;
1394
e = build_load_error_hp(hp, errcode);
1396
mess = TUPLE2(hp,tag,e);
1398
mess = TUPLE5(hp,type,r,am_driver,driver_name,mess);
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);
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;
1410
static void notify_all(DE_Handle *dh, char *name, Uint awaiting, Eterm type, Eterm tag)
1415
while (*p != NULL) {
1416
if ((*p)->awaiting_status == awaiting) {
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);
1430
typedef struct errcode_entry {
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},
1447
static int errdesc_to_code(Eterm errdesc, int *code /* out */)
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;
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])) {
1466
*code = signed_val(tp[2]);
1472
static Eterm build_load_error(Process *p, int code)
1474
int need = load_error_need(code);
1476
ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(p));
1478
hp = HAlloc(p,need);
1480
return build_load_error_hp(hp,code);
1483
static int load_error_need(int code)
1485
ErrcodeEntry *ee = errcode_tab;
1486
while (ee->atm != NULL) {
1487
if (ee->code == code) {
1495
static Eterm build_load_error_hp(Eterm *hp, int code)
1497
ErrcodeEntry *ee = errcode_tab;
1498
while (ee->atm != NULL) {
1499
if (ee->code == code) {
1500
return mkatom(ee->atm);
1504
return TUPLE2(hp,am_open_error, make_small(code));
1509
static Eterm mkatom(char *str)
1511
return am_atom_put(str, sys_strlen(str));
1514
static char *pick_list_or_atom(Eterm name_term)
1518
if (is_atom(name_term)) {
1519
Atom *ap = atom_tab(atom_val(name_term));
1521
/* If io_lists with zero length is not allowed,
1522
then the empty atom shouldn't */
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';
1529
name_len = io_list_len(name_term);
1530
if (name_len <= 0) {
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) {
1537
name[name_len] = '\0';
1542
erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
1547
static int build_proc_info(DE_Handle *dh, ProcEntryInfo **out_pei, Uint filter)
1549
ProcEntryInfo *pei = NULL;
1551
int num_pei_allocated = 0;
1555
ERTS_SMP_LC_ASSERT(erts_smp_lc_io_is_locked());
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) {
1563
for (i = 0; i < num_pei; ++i) {
1564
if (pei[i].pid == id && pei[i].status == stat) {
1571
if (num_pei >= num_pei_allocated) {
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));
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;
1591
static DE_List *lookup_driver(char *name)
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)