awesome/common/signal.h
Uli Schlachter 75ed165ae6 Test & fix a bug with dbus.disconnect_signal (#1096)
The code was written so that it assumes that disconnecting the last signal also
removed the corresponding entry in the signal array. This lead e.g. to an
index-out-of-bounds access in some cases.

Signed-off-by: Uli Schlachter <psychon@znc.in>
2016-09-18 12:50:40 +02:00

105 lines
2.9 KiB
C

/*
* common/signal.h - Signal handling functions
*
* Copyright © 2009 Julien Danjou <julien@danjou.info>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef AWESOME_COMMON_SIGNAL
#define AWESOME_COMMON_SIGNAL
#include "common/array.h"
DO_ARRAY(const void *, cptr, DO_NOTHING)
typedef struct
{
unsigned long id;
cptr_array_t sigfuncs;
} signal_t;
static inline int
signal_cmp(const void *a, const void *b)
{
const signal_t *x = a, *y = b;
return x->id > y->id ? 1 : (x->id < y->id ? -1 : 0);
}
static inline void
signal_wipe(signal_t *sig)
{
cptr_array_wipe(&sig->sigfuncs);
}
DO_BARRAY(signal_t, signal, signal_wipe, signal_cmp)
static inline signal_t *
signal_array_getbyid(signal_array_t *arr, unsigned long id)
{
signal_t sig = { .id = id };
return signal_array_lookup(arr, &sig);
}
/** Connect a signal inside a signal array.
* You are in charge of reference counting.
* \param arr The signal array.
* \param name The signal name.
* \param ref The reference to add.
*/
static inline void
signal_connect(signal_array_t *arr, const char *name, const void *ref)
{
unsigned long tok = a_strhash((const unsigned char *) name);
signal_t *sigfound = signal_array_getbyid(arr, tok);
if(sigfound)
cptr_array_append(&sigfound->sigfuncs, ref);
else
{
signal_t sig = { .id = tok };
cptr_array_append(&sig.sigfuncs, ref);
signal_array_insert(arr, sig);
}
}
/** Disconnect a signal inside a signal array.
* You are in charge of reference counting.
* \param arr The signal array.
* \param name The signal name.
* \param ref The reference to remove.
*/
static inline bool
signal_disconnect(signal_array_t *arr, const char *name, const void *ref)
{
signal_t *sigfound = signal_array_getbyid(arr,
a_strhash((const unsigned char *) name));
if(sigfound)
{
foreach(func, sigfound->sigfuncs)
if(ref == *func)
{
cptr_array_remove(&sigfound->sigfuncs, func);
if(sigfound->sigfuncs.len == 0)
signal_array_remove(arr, sigfound);
return true;
}
}
return false;
}
#endif
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80