resource.c 3.97 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
 */

#include "resource.h"

30
#include "gc.h"
Niels Möller's avatar
Niels Möller committed
31
32
33
#include "werror.h"
#include "xalloc.h"

34
35
#include <assert.h>

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

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

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

44
45
46
47
48
49
50
51
/* 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
52

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


/* Sanity check */
57

58
59
void
dont_free_live_resource(int alive)
Niels Möller's avatar
Niels Möller committed
60
61
{
  if (alive)
62
63
    fatal("dont_free_live_resource: "
          "garbage collecting a live resource!\n");
Niels Möller's avatar
Niels Möller committed
64
65
}

66
67
68
69
70
71
72
/* 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
73
init_resource(struct resource *self,
74
75
76
77
78
79
	      void (*k)(struct resource *))
{
  self->alive = 1;
  self->kill = k ? k : do_resource_kill;
}

80
81
82
83
84
/* 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
85
{
86
87
88
89
  struct resource_node *next;
  struct resource *resource;
};

Niels Möller's avatar
Niels Möller committed
90
/* Works as a weak list of resources. */
91
92
93
94
95
96
97
98
99
100
/* 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
struct resource_list *
179
make_resource_list(void)
Niels Möller's avatar
Niels Möller committed
180
{
181
  NEW(concrete_resource_list, self);
182
  init_resource(&self->super.super, do_kill_all);
Niels Möller's avatar
Niels Möller committed
183

184
  trace("make_resource_list: created %xi\n", self);
185
186
187
  self->super.remember = do_remember_resource;
  
  self->q = NULL;
Niels Möller's avatar
Niels Möller committed
188

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