e576bb2002-10-11Martin Nilsson /* || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */
aedfb12002-10-09Martin Nilsson 
bcf9461998-01-27Fredrik Hübinette (Hubbe) #include "global.h"
bb55f81997-03-16Fredrik Hübinette (Hubbe) #include "pike_macros.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "callback.h"
b2d3e42000-12-01Fredrik Hübinette (Hubbe) #include "pike_error.h"
6eff5e2013-10-09Arne Goedeke #include "block_allocator.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) 
ee3e5c1997-09-17Fredrik Hübinette (Hubbe) struct callback_list fork_child_callback;
52829c1996-08-03Fredrik Hübinette (Hubbe) /* * This file is used to simplify the management of callbacks when certain * events occur. The callbacks are managed as linked lists, allocated in * chunks. */ /* FIXME: free all chunks of memory at exit */
8f4f881996-06-20Fredrik Hübinette (Hubbe) struct callback
5267b71995-08-09Fredrik Hübinette (Hubbe) {
8f4f881996-06-20Fredrik Hübinette (Hubbe)  struct callback *next; callback_func call; callback_func free_func; void *arg;
5267b71995-08-09Fredrik Hübinette (Hubbe) };
8f4f881996-06-20Fredrik Hübinette (Hubbe) #define CALLBACK_CHUNK 128
d476592013-06-12Arne Goedeke  static struct block_allocator callback_allocator = BA_INIT(sizeof(struct callback), CALLBACK_CHUNK); void count_memory_in_callbacks(size_t * num, size_t * size) { ba_count_all(&callback_allocator, num, size); }
5267b71995-08-09Fredrik Hübinette (Hubbe) 
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
c3c7031996-12-04Fredrik Hübinette (Hubbe) extern int d_flag;
81b84e1996-12-03Fredrik Hübinette (Hubbe) static void check_callback_chain(struct callback_list *lst) {
1abbfb2006-07-05Martin Stjernholm  int len=0;
81b84e1996-12-03Fredrik Hübinette (Hubbe)  struct callback *foo;
6a0dd12001-09-04Fredrik Hübinette (Hubbe)  if(d_flag>4)
81b84e1996-12-03Fredrik Hübinette (Hubbe)  {
c3c7031996-12-04Fredrik Hübinette (Hubbe)  for(foo=lst->callbacks;foo;foo=foo->next)
81b84e1996-12-03Fredrik Hübinette (Hubbe)  {
14003a2017-05-18Per Cederqvist  if((len & 1023)==1023)
81b84e1996-12-03Fredrik Hübinette (Hubbe)  {
c3c7031996-12-04Fredrik Hübinette (Hubbe)  int len2=0; struct callback *tmp; for(tmp=foo->next;tmp && len2<=len;tmp=tmp->next) {
6f52402003-11-14Martin Stjernholm #ifdef PIKE_DEBUG
c3c7031996-12-04Fredrik Hübinette (Hubbe)  if(tmp==foo)
5aad932002-08-15Marcus Comstedt  Pike_fatal("Callback list is cyclic!!!\n");
6f52402003-11-14Martin Stjernholm #endif
c3c7031996-12-04Fredrik Hübinette (Hubbe)  }
81b84e1996-12-03Fredrik Hübinette (Hubbe)  }
c3c7031996-12-04Fredrik Hübinette (Hubbe)  len++;
81b84e1996-12-03Fredrik Hübinette (Hubbe)  } } } #else #define check_callback_chain(X) #endif
4a083c2014-11-14Henrik Grubbström (Grubba) /** * Traverse a linked list of callbacks and call all the active callbacks
52829c1996-08-03Fredrik Hübinette (Hubbe)  * in the list. Deactivated callbacks are freed and placed in the free list. */
e067e62001-08-30Fredrik Hübinette (Hubbe) PMOD_EXPORT void low_call_callback(struct callback_list *lst, void *arg)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
81b84e1996-12-03Fredrik Hübinette (Hubbe)  int this_call; struct callback *l,**ptr; lst->num_calls++; this_call=lst->num_calls; check_callback_chain(lst); ptr=&lst->callbacks;
9c6f7d1997-04-15Fredrik Hübinette (Hubbe)  while((l=*ptr))
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
81b84e1996-12-03Fredrik Hübinette (Hubbe)  if(l->call) { l->call(l,l->arg, arg); if(lst->num_calls != this_call) return; }
8f4f881996-06-20Fredrik Hübinette (Hubbe)  if(!l->call)
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
c3c7031996-12-04Fredrik Hübinette (Hubbe)  if(l->free_func) l->free_func(l, l->arg, 0);
bf45771996-12-05Fredrik Hübinette (Hubbe)  while(*ptr != l) { ptr=&(ptr[0]->next);
6f52402003-11-14Martin Stjernholm #ifdef PIKE_DEBUG
bf45771996-12-05Fredrik Hübinette (Hubbe)  if(!*ptr) { /* We totally failed to find where we are in the linked list.. */
5aad932002-08-15Marcus Comstedt  Pike_fatal("Callback linked list breakdown.\n");
bf45771996-12-05Fredrik Hübinette (Hubbe)  }
6f52402003-11-14Martin Stjernholm #endif
bf45771996-12-05Fredrik Hübinette (Hubbe)  }
5267b71995-08-09Fredrik Hübinette (Hubbe)  *ptr=l->next;
d476592013-06-12Arne Goedeke  ba_free(&callback_allocator, l);
ddea551996-07-01Fredrik Hübinette (Hubbe)  }else{ ptr=& l->next;
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
81b84e1996-12-03Fredrik Hübinette (Hubbe)  check_callback_chain(lst);
5267b71995-08-09Fredrik Hübinette (Hubbe)  } }
4a083c2014-11-14Henrik Grubbström (Grubba) /** * Add a callback to the linked list pointed to by ptr. */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct callback *debug_add_to_callback(struct callback_list *lst,
4a083c2014-11-14Henrik Grubbström (Grubba)  callback_func call, void *arg, callback_func free_func)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
8f4f881996-06-20Fredrik Hübinette (Hubbe)  struct callback *l;
dc8d022014-04-27Martin Nilsson  l=ba_alloc(&callback_allocator);
8f4f881996-06-20Fredrik Hübinette (Hubbe)  l->call=call; l->arg=arg;
c3c7031996-12-04Fredrik Hübinette (Hubbe)  l->free_func=free_func;
8f4f881996-06-20Fredrik Hübinette (Hubbe) 
81b84e1996-12-03Fredrik Hübinette (Hubbe)  l->next=lst->callbacks; lst->callbacks=l; check_callback_chain(lst);
5267b71995-08-09Fredrik Hübinette (Hubbe)  return l; }
4a083c2014-11-14Henrik Grubbström (Grubba) /** * Deactivates a callback. * It is not actually freed until next time the callback is "called".
8f4f881996-06-20Fredrik Hübinette (Hubbe)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void *remove_callback(struct callback *l)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
8f4f881996-06-20Fredrik Hübinette (Hubbe)  l->call=0;
c3c7031996-12-04Fredrik Hübinette (Hubbe)  l->free_func=0;
8f4f881996-06-20Fredrik Hübinette (Hubbe)  return l->arg;
5267b71995-08-09Fredrik Hübinette (Hubbe) }
4a083c2014-11-14Henrik Grubbström (Grubba) /** * Free all the callbacks in a linked list of callbacks. */
4e11571998-03-21Fredrik Hübinette (Hubbe) void free_callback_list(struct callback_list *lst)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
81b84e1996-12-03Fredrik Hübinette (Hubbe)  struct callback *l,**ptr; check_callback_chain(lst); ptr=& lst->callbacks;
9c6f7d1997-04-15Fredrik Hübinette (Hubbe)  while((l=*ptr))
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
c3c7031996-12-04Fredrik Hübinette (Hubbe)  if(l->free_func)
ddea551996-07-01Fredrik Hübinette (Hubbe)  l->free_func(l, l->arg, 0);
5267b71995-08-09Fredrik Hübinette (Hubbe)  *ptr=l->next;
d476592013-06-12Arne Goedeke  ba_free(&callback_allocator, l);
5267b71995-08-09Fredrik Hübinette (Hubbe)  } }
4a083c2014-11-14Henrik Grubbström (Grubba) /** * Free all callbacks. */
be478c1997-08-30Henrik Grubbström (Grubba) void cleanup_callbacks(void)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
d476592013-06-12Arne Goedeke  ba_destroy(&callback_allocator);
5267b71995-08-09Fredrik Hübinette (Hubbe) }