Skip to content

Commit c2e9ba7

Browse files
committed
Avoid memory leaks when removing function helpers
1 parent b9484be commit c2e9ba7

File tree

2 files changed

+44
-14
lines changed

2 files changed

+44
-14
lines changed

roseus/euslisp/roseus.l

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@
1414

1515
(in-package "ROS")
1616

17+
(defvar ros::*compile-message* nil)
18+
(defvar ros::*static-data-vector*
19+
(vector
20+
(make-hash-table :size 32 :test #'string=) ;; s_mapSubscribed
21+
(make-hash-table :size 32 :test #'string=) ;; s_mapServiced
22+
(make-hash-table :size 16 :test #'string=) ;; s_mapTimered
23+
))
24+
25+
1726
(defun ros::roseus-sigint-handler (sig)
1827
(ros::ros-error "Received shutdown request (SIGINT)")
1928
(exit 1))
@@ -55,8 +64,6 @@
5564
(ros::set-logger-level level)
5665
)))
5766

58-
(setq ros::*compile-message* nil)
59-
6067
(shadow 'object *package*)
6168
(defclass ros::object
6269
:super propertied-object

roseus/roseus.cpp

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,12 @@ static bool s_bInstalled = false;
198198
#define s_mapTimered s_staticdata.mapTimered
199199
#define s_mapHandle s_staticdata.mapHandle
200200

201+
#define s_mapSubscribedIndex 0
202+
#define s_mapServicedIndex 1
203+
#define s_mapTimeredIndex 2
204+
201205
pointer K_ROSEUS_MD5SUM,K_ROSEUS_DATATYPE,K_ROSEUS_DEFINITION,K_ROSEUS_CONNECTION_HEADER,K_ROSEUS_SERIALIZATION_LENGTH,K_ROSEUS_SERIALIZE,K_ROSEUS_DESERIALIZE,K_ROSEUS_INIT,K_ROSEUS_GET,K_ROSEUS_REQUEST,K_ROSEUS_RESPONSE,K_ROSEUS_GROUPNAME,K_ROSEUS_ONESHOT,K_ROSEUS_LAST_EXPECTED,K_ROSEUS_LAST_REAL,K_ROSEUS_CURRENT_EXPECTED,K_ROSEUS_CURRENT_REAL,K_ROSEUS_LAST_DURATION,K_ROSEUS_SEC,K_ROSEUS_NSEC,QANON,QNOOUT,QREPOVERSION,QROSDEBUG,QROSINFO,QROSWARN,QROSERROR,QROSFATAL;
206+
pointer QSTATICDATAVECTOR, K_ROSEUS_ENTER, K_ROSEUS_DELETE;
202207
extern pointer LAMCLOSURE;
203208

204209
/***********************************************************
@@ -256,14 +261,21 @@ int getInteger(pointer message, pointer method) {
256261
return 0;
257262
}
258263

259-
void store_pointer(context *ctx, pointer value) {
260-
// Stores a callback list as a symbol in the lisp package.
264+
void store_pointer(context *ctx, string name, int index, pointer value) {
265+
// Stores a callback list in ros::*static-data-vector*
261266
// This prevents that the callable gets collected by the gc,
262267
// even if there are no other references to it.
263-
// TODO: cleanup when unsubscribed
264268
vpush(value);
265-
pointer p=gensym(ctx);
266-
defconst(ctx, (char*)(p->c.sym.pname->c.str.chars), vpop(), lisppkg);
269+
pointer p=makestring((char *)name.c_str(), name.size());
270+
csend(ctx,speval(QSTATICDATAVECTOR)->c.vec.v[index],K_ROSEUS_ENTER,2,p,vpop());
271+
}
272+
273+
void erase_pointer(context *ctx, string name, int index) {
274+
// Removes the entry for ros::*static-data-vector*,
275+
// meaning that the pointers can be deallocated if
276+
// there are no other references to them.
277+
pointer p=makestring((char *)name.c_str(), name.size());
278+
csend(ctx,speval(QSTATICDATAVECTOR)->c.vec.v[index],K_ROSEUS_DELETE,1,p);
267279
}
268280

269281
class EuslispMessage
@@ -410,7 +422,9 @@ class EuslispSubscriptionCallbackHelper : public ros::SubscriptionCallbackHelper
410422
pointer _scb,_args;
411423
EuslispMessage _msg;
412424

413-
EuslispSubscriptionCallbackHelper(pointer scb, pointer args,pointer tmpl) : _args(args), _msg(tmpl) {
425+
EuslispSubscriptionCallbackHelper(string name, pointer scb, pointer args, pointer tmpl) :
426+
_args(args), _msg(tmpl)
427+
{
414428
context *ctx = current_ctx;
415429
//ROS_WARN("func");prinx(ctx,scb,ERROUT);flushstream(ERROUT);terpri(ERROUT);
416430
//ROS_WARN("argc");prinx(ctx,args,ERROUT);flushstream(ERROUT);terpri(ERROUT);
@@ -426,7 +440,7 @@ class EuslispSubscriptionCallbackHelper : public ros::SubscriptionCallbackHelper
426440
ROS_ERROR("subscription callback function install error");
427441
}
428442
// avoid gc
429-
store_pointer(ctx, cons(ctx,scb,args));
443+
store_pointer(ctx, name, s_mapSubscribedIndex, cons(ctx,scb,args));
430444
}
431445
~EuslispSubscriptionCallbackHelper() {
432446
ROS_ERROR("subscription gc");
@@ -489,7 +503,9 @@ class EuslispServiceCallbackHelper : public ros::ServiceCallbackHelper {
489503
string md5, datatype, requestDataType, responseDataType,
490504
requestMessageDefinition, responseMessageDefinition;
491505

492-
EuslispServiceCallbackHelper(pointer scb, pointer args, string smd5, string sdatatype, pointer reqclass, pointer resclass) : _args(args), _req(reqclass), _res(resclass), md5(smd5), datatype(sdatatype) {
506+
EuslispServiceCallbackHelper(string name, pointer scb, pointer args, string smd5, string sdatatype, pointer reqclass, pointer resclass) :
507+
_args(args), _req(reqclass), _res(resclass), md5(smd5), datatype(sdatatype)
508+
{
493509
context *ctx = current_ctx;
494510
//ROS_WARN("func");prinx(ctx,scb,ERROUT);flushstream(ERROUT);terpri(ERROUT);
495511
//ROS_WARN("argc");prinx(ctx,args,ERROUT);flushstream(ERROUT);terpri(ERROUT);
@@ -506,7 +522,7 @@ class EuslispServiceCallbackHelper : public ros::ServiceCallbackHelper {
506522
ROS_ERROR("service callback function install error");
507523
}
508524
// avoid gc
509-
store_pointer(ctx, cons(ctx,scb,args));
525+
store_pointer(ctx, name, s_mapServicedIndex, cons(ctx,scb,args));
510526

511527
requestDataType = _req.__getDataType();
512528
responseDataType = _res.__getDataType();
@@ -667,6 +683,8 @@ pointer ROSEUS(register context *ctx,int n,pointer *argv)
667683
K_ROSEUS_LAST_DURATION = defkeyword(ctx,"LAST-DURATION");
668684
K_ROSEUS_SEC = defkeyword(ctx,"SEC");
669685
K_ROSEUS_NSEC = defkeyword(ctx,"NSEC");
686+
K_ROSEUS_ENTER = defkeyword(ctx,"ENTER");
687+
K_ROSEUS_DELETE = defkeyword(ctx,"DELETE");
670688

671689
s_mapAdvertised.clear();
672690
s_mapSubscribed.clear();
@@ -949,7 +967,7 @@ pointer ROSEUS_SUBSCRIBE(register context *ctx,int n,pointer *argv)
949967
EuslispMessage msg(message);
950968
boost::shared_ptr<SubscriptionCallbackHelper> *callback =
951969
(new boost::shared_ptr<SubscriptionCallbackHelper>
952-
(new EuslispSubscriptionCallbackHelper(fncallback, args, message)));
970+
(new EuslispSubscriptionCallbackHelper(topicname, fncallback, args, message)));
953971
SubscribeOptions so(topicname, queuesize, msg.__getMD5Sum(), msg.__getDataType());
954972
so.helper = *callback;
955973
Subscriber subscriber = lnode->subscribe(so);
@@ -972,6 +990,7 @@ pointer ROSEUS_UNSUBSCRIBE(register context *ctx,int n,pointer *argv)
972990
else error(E_NOSTRING);
973991

974992
bool bSuccess = s_mapSubscribed.erase(topicname)>0;
993+
erase_pointer(ctx, topicname, s_mapSubscribedIndex);
975994

976995
return (bSuccess?T:NIL);
977996
}
@@ -1337,7 +1356,7 @@ pointer ROSEUS_ADVERTISE_SERVICE(register context *ctx,int n,pointer *argv)
13371356
pointer response(csend(ctx,emessage,K_ROSEUS_GET,1,K_ROSEUS_RESPONSE));
13381357
boost::shared_ptr<EuslispServiceCallbackHelper> *callback =
13391358
(new boost::shared_ptr<EuslispServiceCallbackHelper>
1340-
(new EuslispServiceCallbackHelper(fncallback, args, message.__getMD5Sum(),
1359+
(new EuslispServiceCallbackHelper(service, fncallback, args, message.__getMD5Sum(),
13411360
message.__getDataType(), request, response)));
13421361
vpop(); // pop args
13431362

@@ -1369,6 +1388,7 @@ pointer ROSEUS_UNADVERTISE_SERVICE(register context *ctx,int n,pointer *argv)
13691388

13701389
ROS_DEBUG("unadvertise %s", service.c_str());
13711390
bool bSuccess = s_mapServiced.erase(service)>0;
1391+
erase_pointer(ctx, service, s_mapServicedIndex);
13721392

13731393
return (bSuccess?T:NIL);
13741394
}
@@ -2002,6 +2022,7 @@ class TimerFunction
20022022
// unregister callback when finished
20032023
if (_oneshot) {
20042024
bool bSuccess = s_mapTimered.erase(_funcname)>0;
2025+
erase_pointer(ctx, _funcname, s_mapTimeredIndex);
20052026
if (bSuccess) {
20062027
ROS_DEBUG("one shot timer successfully exited: %s", _funcname.c_str());
20072028
}
@@ -2088,7 +2109,7 @@ pointer ROSEUS_CREATE_TIMER(register context *ctx,int n,pointer *argv)
20882109
for (int i=n-1;i>=2;i--) args=cons(ctx,argv[i],args);
20892110

20902111
// avoid gc
2091-
store_pointer(ctx, cons(ctx,fncallback,args));
2112+
store_pointer(ctx, fncallname, s_mapTimeredIndex, cons(ctx,fncallback,args));
20922113

20932114
// ;; store mapTimered
20942115
ROS_DEBUG("create timer %s at %f (oneshot=%d) (groupname=%s)", fncallname.c_str(), period, oneshot, groupname.c_str());
@@ -2124,6 +2145,8 @@ pointer ___roseus(register context *ctx, int n, pointer *argv, pointer env)
21242145
QROSWARN=defvar(ctx,"*ROSWARN*",makeint(3),rospkg);
21252146
QROSERROR=defvar(ctx,"*ROSERROR*",makeint(4),rospkg);
21262147
QROSFATAL=defvar(ctx,"*ROSFATAL*",makeint(5),rospkg);
2148+
QSTATICDATAVECTOR=intern(ctx,"*STATIC-DATA-VECTOR*",20,rospkg);
2149+
21272150
defun(ctx,"SPIN",argv[0],(pointer (*)())ROSEUS_SPIN, "Enter simple event loop");
21282151

21292152
defun(ctx,"SPIN-ONCE",argv[0],(pointer (*)())ROSEUS_SPINONCE,

0 commit comments

Comments
 (0)