resource.c 3.96 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* resource.c
 *
 * External resources associated with a connection, for instance
 * processes and ports. Used to kill or release the resource in
 * question when the connection dies.
 *
 * $Id$ */

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 1998 Niels Mller
 *
 * 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
J.H.M. Dassen's avatar
J.H.M. Dassen committed
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Niels Möller's avatar
Niels Möller committed
26
27
28
29
30
31
32
 */

#include "resource.h"

#include "werror.h"
#include "xalloc.h"

33
34
#include <assert.h>

Niels Möller's avatar
Niels Möller committed
35
/* Prototypes */
36

Niels Möller's avatar
Niels Möller committed
37
38
void dont_free_live_resource(int alive);

39
#define GABA_DEFINE
Niels Möller's avatar
Niels Möller committed
40
#include "resource.h.x"
41
#undef GABA_DEFINE
Niels Möller's avatar
Niels Möller committed
42

43
44
45
46
47
48
49
50
/* Forward declarations */

struct resource_node;

void do_mark_resources(struct resource_node **q,
		       void (*mark)(struct lsh_object *o));

void do_free_resources(struct resource_node **q);
Niels Möller's avatar
Niels Möller committed
51

52
53
54
55
#include "resource.c.x"


/* Sanity check */
56
57
58

/* NOTE: This happens normally during gc_final. Under all other
 * circumstances, it's a serious error. */
59
60
void
dont_free_live_resource(int alive)
Niels Möller's avatar
Niels Möller committed
61
62
{
  if (alive)
63
64
    werror("dont_free_live_resource: "
	   "garbage collecting a live resource!\n");
Niels Möller's avatar
Niels Möller committed
65
66
}

67
68
69
70
71
72
73
74
75
76
77
78
79
80
/* For resources that are only marked as dead, and taken care of
 * later. */
static void
do_resource_kill(struct resource *self)
{ self->alive = 0; }

void
resource_init(struct resource *self,
	      void (*k)(struct resource *))
{
  self->alive = 1;
  self->kill = k ? k : do_resource_kill;
}

81
82
83
84
85
/* The behaviour of a resource list is somewhat similar to
 * a weak list. Nodes that are dead are unlinked automatically,
 * so that they can be garbage collected. */

struct resource_node
Niels Möller's avatar
Niels Möller committed
86
{
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  struct resource_node *next;
  struct resource *resource;
};

/* GABA:
   (class
     (name concrete_resource_list)
     (super resource_list)
     (vars
       (q indirect-special "struct resource_node *"
                           do_mark_resources do_free_resources)))
*/

/* Loop over the resources, mark the living and unlink the dead. */
101
102
103
void
do_mark_resources(struct resource_node **q,
		  void (*mark)(struct lsh_object *o))
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
{
  struct resource_node *n;
  
  while ( (n = *q) )
    {
      if (n->resource->alive)
	{
	  mark(&n->resource->super);
	  q = &n->next;
	}
      else
	{
	  *q = n->next;
	  lsh_space_free(n);
	}
    }
Niels Möller's avatar
Niels Möller committed
120
121
}

122
/* Free the list. */
123
124
void
do_free_resources(struct resource_node **q)
Niels Möller's avatar
Niels Möller committed
125
{
126
127
128
  struct resource_node *n;

  for (n = *q; n; )
129
    {
130
131
132
133
134
135
136
137
138
139
140
141
142
143
      struct resource_node *old = n;
      n = n->next;
      lsh_space_free(old);
    }
}


static void
do_remember_resource(struct resource_list *s,
		     struct resource *resource)
{
  CAST(concrete_resource_list, self, s);
  struct resource_node *n;

144
145
146
  if (!self->super.super.alive)
    {
      werror("do_remember_resource: resource list is already dead.\n");
147
      KILL_RESOURCE(resource);
148
149
150
      return;
    }
  
151
152
153
154
155
156
157
  NEW_SPACE(n);

  n->resource = resource;
  n->next = self->q;
  self->q = n;
}

158
159
static void
do_kill_all(struct resource *s)
160
161
162
163
164
165
166
{
  CAST(concrete_resource_list, self, s);
  struct resource_node *n;

  for (n = self->q; n; )
    {
      CAST_SUBTYPE(resource, r, n->resource);
Niels Möller's avatar
Niels Möller committed
167
      struct resource_node *old = n;
168

169
      KILL_RESOURCE(r);
170
171
172
      n = n->next;

      lsh_space_free(old);
173
    }
174
175
  self->q = NULL;
  self->super.super.alive = 0;
Niels Möller's avatar
Niels Möller committed
176
177
}
  
178
179
struct resource_list *
empty_resource_list(void)
Niels Möller's avatar
Niels Möller committed
180
{
181
  NEW(concrete_resource_list, self);
182
  resource_init(&self->super.super, do_kill_all);
Niels Möller's avatar
Niels Möller committed
183

184
185
186
  self->super.remember = do_remember_resource;
  
  self->q = NULL;
Niels Möller's avatar
Niels Möller committed
187

188
  return &self->super;
Niels Möller's avatar
Niels Möller committed
189
}