Change events to have an array of "void *" references, and give the
event posting functions varargs to fill these. Attribute g_call_me() to appropriate g_geom's where necessary. Add a flag argument to g_call_me() methods which will be used to signal cancellation of events in the future. This commit should be a no-op.
This commit is contained in:
parent
7d7d429762
commit
afcbcfaed0
@ -220,8 +220,8 @@ void g_trace(int level, const char *, ...);
|
||||
|
||||
|
||||
/* geom_event.c */
|
||||
typedef void g_call_me_t(void *);
|
||||
int g_call_me(g_call_me_t *func, void *arg);
|
||||
typedef void g_call_me_t(void *, int flag);
|
||||
int g_call_me(g_call_me_t *func, void *arg, ...);
|
||||
void g_orphan_provider(struct g_provider *pp, int error);
|
||||
void g_waitidle(void);
|
||||
|
||||
|
@ -479,7 +479,7 @@ g_bsd_try(struct g_geom *gp, struct g_slicer *gsp, struct g_consumer *cp, int se
|
||||
*/
|
||||
|
||||
static void
|
||||
g_bsd_ioctl(void *arg)
|
||||
g_bsd_ioctl(void *arg, int flag __unused)
|
||||
{
|
||||
struct bio *bp;
|
||||
struct g_geom *gp;
|
||||
@ -608,7 +608,7 @@ g_bsd_diocbsdbb(dev_t dev, u_long cmd __unused, caddr_t data, int fflag __unused
|
||||
* footshooting as best we can.
|
||||
*/
|
||||
static void
|
||||
g_bsd_hotwrite(void *arg)
|
||||
g_bsd_hotwrite(void *arg, int flag __unused)
|
||||
{
|
||||
struct bio *bp;
|
||||
struct g_geom *gp;
|
||||
@ -682,7 +682,7 @@ g_bsd_start(struct bio *bp)
|
||||
/* We do not allow deleting our hot spots */
|
||||
return (EPERM);
|
||||
case BIO_WRITE:
|
||||
g_call_me(g_bsd_hotwrite, bp);
|
||||
g_call_me(g_bsd_hotwrite, bp, gp, NULL);
|
||||
return (EJUSTRETURN);
|
||||
case BIO_GETATTR:
|
||||
if (g_handleattr(bp, "BSD::labelsum", ms->labelsum,
|
||||
@ -723,7 +723,7 @@ g_bsd_start(struct bio *bp)
|
||||
* some I/O requests. Ask the event-handler to schedule
|
||||
* us in a less restricted environment.
|
||||
*/
|
||||
error = g_call_me(g_bsd_ioctl, bp);
|
||||
error = g_call_me(g_bsd_ioctl, bp, gp, NULL);
|
||||
if (error)
|
||||
g_io_deliver(bp, error);
|
||||
/*
|
||||
|
@ -294,7 +294,7 @@ g_disk_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g
|
||||
}
|
||||
|
||||
static void
|
||||
g_disk_create(void *arg)
|
||||
g_disk_create(void *arg, int flag __unused)
|
||||
{
|
||||
struct g_geom *gp;
|
||||
struct g_provider *pp;
|
||||
@ -335,7 +335,7 @@ disk_create(int unit, struct disk *dp, int flags, void *unused __unused, void *
|
||||
dp->d_devstat = devstat_new_entry(dp->d_name, dp->d_unit,
|
||||
dp->d_sectorsize, DEVSTAT_ALL_SUPPORTED,
|
||||
DEVSTAT_TYPE_DIRECT, DEVSTAT_PRIORITY_MAX);
|
||||
g_call_me(g_disk_create, dp);
|
||||
g_call_me(g_disk_create, dp, dp, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
@ -351,7 +351,7 @@ disk_destroy(struct disk *dp)
|
||||
}
|
||||
|
||||
static void
|
||||
g_kern_disks(void *p)
|
||||
g_kern_disks(void *p, int flag __unused)
|
||||
{
|
||||
struct sbuf *sb;
|
||||
struct g_geom *gp;
|
||||
@ -376,7 +376,7 @@ sysctl_disks(SYSCTL_HANDLER_ARGS)
|
||||
|
||||
sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
|
||||
sbuf_clear(sb);
|
||||
error = g_call_me(g_kern_disks, sb);
|
||||
error = g_call_me(g_kern_disks, sb, NULL);
|
||||
while (!error && !sbuf_done(sb)) {
|
||||
tsleep(sb, PZERO, "kern.disks", hz);
|
||||
}
|
||||
|
@ -40,6 +40,8 @@
|
||||
#ifdef _KERNEL
|
||||
|
||||
#include <sys/queue.h>
|
||||
#include <sys/_lock.h>
|
||||
#include <sys/_mutex.h>
|
||||
|
||||
typedef int disk_open_t(struct disk *);
|
||||
typedef int disk_close_t(struct disk *);
|
||||
@ -60,6 +62,8 @@ struct disk {
|
||||
u_int d_flags;
|
||||
const char *d_name;
|
||||
u_int d_unit;
|
||||
struct bio_queue_head *d_queue;
|
||||
struct mtx *d_lock;
|
||||
|
||||
/* Disk methods */
|
||||
disk_open_t *d_open;
|
||||
|
@ -101,7 +101,7 @@ g_confdot_class(struct sbuf *sb, struct g_class *mp)
|
||||
}
|
||||
|
||||
void
|
||||
g_confdot(void *p)
|
||||
g_confdot(void *p, int flag __unused)
|
||||
{
|
||||
struct g_class *mp;
|
||||
struct sbuf *sb;
|
||||
@ -143,7 +143,7 @@ g_conftxt_class(struct sbuf *sb, struct g_class *mp)
|
||||
}
|
||||
|
||||
void
|
||||
g_conftxt(void *p)
|
||||
g_conftxt(void *p, int flag __unused)
|
||||
{
|
||||
struct g_class *mp;
|
||||
struct sbuf *sb;
|
||||
@ -263,7 +263,7 @@ g_conf_specific(struct sbuf *sb, struct g_class *mp, struct g_geom *gp, struct g
|
||||
}
|
||||
|
||||
void
|
||||
g_confxml(void *p)
|
||||
g_confxml(void *p, int flag __unused)
|
||||
{
|
||||
|
||||
g_topology_assert();
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/eventhandler.h>
|
||||
#include <machine/stdarg.h>
|
||||
#endif
|
||||
#include <sys/errno.h>
|
||||
#include <sys/time.h>
|
||||
@ -158,28 +159,25 @@ g_do_event(struct g_event *ep)
|
||||
struct g_provider *pp;
|
||||
int i;
|
||||
|
||||
g_trace(G_T_TOPOLOGY, "g_do_event(%p) %d m:%p g:%p p:%p c:%p - ",
|
||||
ep, ep->event, ep->class, ep->geom, ep->provider, ep->consumer);
|
||||
g_trace(G_T_TOPOLOGY, "g_do_event(%p) %d - ", ep, ep->event);
|
||||
g_topology_assert();
|
||||
switch (ep->event) {
|
||||
case EV_CALL_ME:
|
||||
ep->func(ep->arg);
|
||||
ep->func(ep->arg, 0);
|
||||
g_topology_assert();
|
||||
break;
|
||||
case EV_NEW_CLASS:
|
||||
mp2 = ep->class;
|
||||
if (g_shutdown)
|
||||
break;
|
||||
mp2 = ep->ref[0];
|
||||
if (mp2->taste == NULL)
|
||||
break;
|
||||
if (g_shutdown)
|
||||
break;
|
||||
LIST_FOREACH(mp, &g_classes, class) {
|
||||
if (mp2 == mp)
|
||||
continue;
|
||||
LIST_FOREACH(gp, &mp->geom, geom) {
|
||||
LIST_FOREACH(pp, &gp->provider, provider) {
|
||||
mp2->taste(ep->class, pp, 0);
|
||||
mp2->taste(mp2, pp, 0);
|
||||
g_topology_assert();
|
||||
}
|
||||
}
|
||||
@ -188,28 +186,26 @@ g_do_event(struct g_event *ep)
|
||||
case EV_NEW_PROVIDER:
|
||||
if (g_shutdown)
|
||||
break;
|
||||
g_trace(G_T_TOPOLOGY, "EV_NEW_PROVIDER(%s)",
|
||||
ep->provider->name);
|
||||
pp = ep->ref[0];
|
||||
g_trace(G_T_TOPOLOGY, "EV_NEW_PROVIDER(%s)", pp->name);
|
||||
LIST_FOREACH(mp, &g_classes, class) {
|
||||
if (mp->taste == NULL)
|
||||
continue;
|
||||
if (!strcmp(ep->provider->name, "geom.ctl") &&
|
||||
strcmp(mp->name, "DEV"))
|
||||
continue;
|
||||
i = 1;
|
||||
LIST_FOREACH(cp, &ep->provider->consumers, consumers)
|
||||
LIST_FOREACH(cp, &pp->consumers, consumers)
|
||||
if(cp->geom->class == mp)
|
||||
i = 0;
|
||||
if (i) {
|
||||
mp->taste(mp, ep->provider, 0);
|
||||
mp->taste(mp, pp, 0);
|
||||
g_topology_assert();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EV_SPOILED:
|
||||
pp = ep->ref[0];
|
||||
g_trace(G_T_TOPOLOGY, "EV_SPOILED(%p(%s),%p)",
|
||||
ep->provider, ep->provider->name, ep->consumer);
|
||||
cp = LIST_FIRST(&ep->provider->consumers);
|
||||
pp, pp->name, ep->ref[1]);
|
||||
cp = LIST_FIRST(&pp->consumers);
|
||||
while (cp != NULL) {
|
||||
cp2 = LIST_NEXT(cp, consumers);
|
||||
if (cp->spoiled) {
|
||||
@ -257,14 +253,6 @@ one_event(void)
|
||||
}
|
||||
TAILQ_REMOVE(&g_events, ep, events);
|
||||
mtx_unlock(&g_eventlock);
|
||||
if (ep->class != NULL)
|
||||
ep->class->event = NULL;
|
||||
if (ep->geom != NULL)
|
||||
ep->geom->event = NULL;
|
||||
if (ep->provider != NULL)
|
||||
ep->provider->event = NULL;
|
||||
if (ep->consumer != NULL)
|
||||
ep->consumer->event = NULL;
|
||||
g_do_event(ep);
|
||||
g_destroy_event(ep);
|
||||
g_pending_events--;
|
||||
@ -284,39 +272,27 @@ g_run_events()
|
||||
}
|
||||
|
||||
void
|
||||
g_post_event(enum g_events ev, struct g_class *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp)
|
||||
g_post_event(enum g_events ev, ...)
|
||||
{
|
||||
struct g_event *ep;
|
||||
va_list ap;
|
||||
void *p;
|
||||
int n;
|
||||
|
||||
g_trace(G_T_TOPOLOGY, "g_post_event(%d, %p, %p, %p, %p)",
|
||||
ev, mp, gp, pp, cp);
|
||||
g_trace(G_T_TOPOLOGY, "g_post_event(%d)", ev);
|
||||
g_topology_assert();
|
||||
ep = g_malloc(sizeof *ep, M_WAITOK | M_ZERO);
|
||||
ep->event = ev;
|
||||
if (mp != NULL) {
|
||||
ep->class = mp;
|
||||
KASSERT(mp->event == NULL, ("Double event on class %d %d",
|
||||
ep->event, mp->event->event));
|
||||
mp->event = ep;
|
||||
}
|
||||
if (gp != NULL) {
|
||||
ep->geom = gp;
|
||||
KASSERT(gp->event == NULL, ("Double event on geom %d %d",
|
||||
ep->event, gp->event->event));
|
||||
gp->event = ep;
|
||||
}
|
||||
if (pp != NULL) {
|
||||
ep->provider = pp;
|
||||
KASSERT(pp->event == NULL, ("Double event on provider %s %d %d",
|
||||
pp->name, ep->event, pp->event->event));
|
||||
pp->event = ep;
|
||||
}
|
||||
if (cp != NULL) {
|
||||
ep->consumer = cp;
|
||||
KASSERT(cp->event == NULL, ("Double event on consumer %d %d",
|
||||
ep->event, cp->event->event));
|
||||
cp->event = ep;
|
||||
va_start(ap, ev);
|
||||
for (n = 0; n < G_N_EVENTREFS; n++) {
|
||||
p = va_arg(ap, void *);
|
||||
if (p == NULL)
|
||||
break;
|
||||
g_trace(G_T_TOPOLOGY, " ref %p", p);
|
||||
ep->ref[n++] = p;
|
||||
}
|
||||
va_end(ap);
|
||||
KASSERT(p == NULL, ("Too many references to event"));
|
||||
mtx_lock(&g_eventlock);
|
||||
g_pending_events++;
|
||||
TAILQ_INSERT_TAIL(&g_events, ep, events);
|
||||
@ -325,36 +301,49 @@ g_post_event(enum g_events ev, struct g_class *mp, struct g_geom *gp, struct g_p
|
||||
}
|
||||
|
||||
void
|
||||
g_cancel_event(struct g_class *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp)
|
||||
g_cancel_event(void *ref)
|
||||
{
|
||||
struct g_event *ep, *epn;
|
||||
u_int n;
|
||||
|
||||
mtx_lock(&g_eventlock);
|
||||
ep = TAILQ_FIRST(&g_events);
|
||||
for (;ep != NULL;) {
|
||||
for (ep = TAILQ_FIRST(&g_events); ep != NULL; ep = epn) {
|
||||
epn = TAILQ_NEXT(ep, events);
|
||||
if (
|
||||
(ep->class != NULL && ep->class == mp) ||
|
||||
(ep->geom != NULL && ep->geom == gp) ||
|
||||
(ep->provider != NULL && ep->provider == pp) ||
|
||||
(ep->consumer != NULL && ep->consumer == cp)) {
|
||||
TAILQ_REMOVE(&g_events, ep, events);
|
||||
g_free(ep);
|
||||
for (n = 0; n < G_N_EVENTREFS; n++) {
|
||||
if (ep->ref[n] == NULL)
|
||||
break;
|
||||
if (ep->ref[n] == ref) {
|
||||
TAILQ_REMOVE(&g_events, ep, events);
|
||||
g_free(ep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ep = epn;
|
||||
}
|
||||
mtx_unlock(&g_eventlock);
|
||||
}
|
||||
|
||||
int
|
||||
g_call_me(g_call_me_t *func, void *arg)
|
||||
g_call_me(g_call_me_t *func, void *arg, ...)
|
||||
{
|
||||
struct g_event *ep;
|
||||
va_list ap;
|
||||
void *p;
|
||||
u_int n;
|
||||
|
||||
g_trace(G_T_TOPOLOGY, "g_call_me(%p, %p", func, arg);
|
||||
ep = g_malloc(sizeof *ep, M_NOWAIT | M_ZERO);
|
||||
if (ep == NULL)
|
||||
return (ENOMEM);
|
||||
va_start(ap, arg);
|
||||
for (n = 0; n < G_N_EVENTREFS; n++) {
|
||||
p = va_arg(ap, void *);
|
||||
if (p == NULL)
|
||||
break;
|
||||
g_trace(G_T_TOPOLOGY, " ref %p", p);
|
||||
ep->ref[n++] = p;
|
||||
}
|
||||
va_end(ap);
|
||||
KASSERT(p == NULL, ("Too many references to event"));
|
||||
ep->event = EV_CALL_ME;
|
||||
ep->func = func;
|
||||
ep->arg = arg;
|
||||
|
@ -66,15 +66,14 @@ enum g_events {
|
||||
EV_LAST
|
||||
};
|
||||
|
||||
#define G_N_EVENTREFS 20
|
||||
|
||||
struct g_event {
|
||||
enum g_events event;
|
||||
TAILQ_ENTRY(g_event) events;
|
||||
struct g_class *class;
|
||||
struct g_geom *geom;
|
||||
struct g_provider *provider;
|
||||
struct g_consumer *consumer;
|
||||
void *arg;
|
||||
g_call_me_t *func;
|
||||
void *ref[G_N_EVENTREFS];
|
||||
};
|
||||
|
||||
/*
|
||||
@ -86,15 +85,15 @@ struct g_event {
|
||||
#define GEOM_MINOR_PROVIDERS 10
|
||||
|
||||
/* geom_dump.c */
|
||||
void g_confxml(void *);
|
||||
void g_confxml(void *, int flag);
|
||||
void g_conf_specific(struct sbuf *sb, struct g_class *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp);
|
||||
void g_confdot(void *);
|
||||
void g_conftxt(void *);
|
||||
void g_confdot(void *, int flag);
|
||||
void g_conftxt(void *, int flag);
|
||||
|
||||
/* geom_event.c */
|
||||
void g_event_init(void);
|
||||
void g_post_event(enum g_events ev, struct g_class *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp);
|
||||
void g_cancel_event(struct g_class *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp);
|
||||
void g_post_event(enum g_events ev, ...);
|
||||
void g_cancel_event(void *ref);
|
||||
void g_run_events(void);
|
||||
void g_stall_events(void);
|
||||
void g_release_events(void);
|
||||
|
@ -161,7 +161,7 @@ sysctl_kern_geom_conftxt(SYSCTL_HANDLER_ARGS)
|
||||
|
||||
sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
|
||||
sbuf_clear(sb);
|
||||
g_call_me(g_conftxt, sb);
|
||||
g_call_me(g_conftxt, sb, NULL);
|
||||
do {
|
||||
tsleep(sb, PZERO, "g_conftxt", hz);
|
||||
} while(!sbuf_done(sb));
|
||||
@ -178,7 +178,7 @@ sysctl_kern_geom_confdot(SYSCTL_HANDLER_ARGS)
|
||||
|
||||
sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
|
||||
sbuf_clear(sb);
|
||||
g_call_me(g_confdot, sb);
|
||||
g_call_me(g_confdot, sb, NULL);
|
||||
do {
|
||||
tsleep(sb, PZERO, "g_confdot", hz);
|
||||
} while(!sbuf_done(sb));
|
||||
@ -195,7 +195,7 @@ sysctl_kern_geom_confxml(SYSCTL_HANDLER_ARGS)
|
||||
|
||||
sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
|
||||
sbuf_clear(sb);
|
||||
g_call_me(g_confxml, sb);
|
||||
g_call_me(g_confxml, sb, NULL);
|
||||
do {
|
||||
tsleep(sb, PZERO, "g_confxml", hz);
|
||||
} while(!sbuf_done(sb));
|
||||
|
@ -173,7 +173,7 @@ g_mbr_modify(struct g_geom *gp, struct g_mbr_softc *ms, u_char *sec0)
|
||||
}
|
||||
|
||||
static void
|
||||
g_mbr_ioctl(void *arg)
|
||||
g_mbr_ioctl(void *arg, int flag __unused)
|
||||
{
|
||||
struct bio *bp;
|
||||
struct g_geom *gp;
|
||||
@ -249,7 +249,7 @@ g_mbr_start(struct bio *bp)
|
||||
* some I/O requests. Ask the event-handler to schedule
|
||||
* us in a less restricted environment.
|
||||
*/
|
||||
error = g_call_me(g_mbr_ioctl, bp);
|
||||
error = g_call_me(g_mbr_ioctl, bp, gp, NULL);
|
||||
if (error)
|
||||
g_io_deliver(bp, error);
|
||||
/*
|
||||
|
@ -160,7 +160,7 @@ g_pc98_modify(struct g_geom *gp, struct g_pc98_softc *ms, u_char *sec)
|
||||
}
|
||||
|
||||
static void
|
||||
g_pc98_ioctl(void *arg)
|
||||
g_pc98_ioctl(void *arg, int flag __unused)
|
||||
{
|
||||
struct bio *bp;
|
||||
struct g_geom *gp;
|
||||
@ -234,7 +234,7 @@ g_pc98_start(struct bio *bp)
|
||||
* some I/O requests. Ask the event-handler to schedule
|
||||
* us in a less restricted environment.
|
||||
*/
|
||||
error = g_call_me(g_pc98_ioctl, bp);
|
||||
error = g_call_me(g_pc98_ioctl, bp, gp, NULL);
|
||||
if (error)
|
||||
g_io_deliver(bp, error);
|
||||
/*
|
||||
|
@ -83,7 +83,7 @@ g_add_class(struct g_class *mp)
|
||||
LIST_INIT(&mp->geom);
|
||||
LIST_INSERT_HEAD(&g_classes, mp, class);
|
||||
if (g_nproviders > 0)
|
||||
g_post_event(EV_NEW_CLASS, mp, NULL, NULL, NULL);
|
||||
g_post_event(EV_NEW_CLASS, mp, NULL);
|
||||
g_topology_unlock();
|
||||
}
|
||||
|
||||
@ -126,7 +126,7 @@ g_destroy_geom(struct g_geom *gp)
|
||||
KASSERT(LIST_EMPTY(&gp->provider),
|
||||
("g_destroy_geom(%s) with provider(s) [%p]",
|
||||
gp->name, LIST_FIRST(&gp->consumer)));
|
||||
g_cancel_event(NULL, gp, NULL, NULL);
|
||||
g_cancel_event(gp);
|
||||
LIST_REMOVE(gp, geom);
|
||||
TAILQ_REMOVE(&geoms, gp, geoms);
|
||||
g_free(gp->name);
|
||||
@ -163,7 +163,7 @@ g_destroy_consumer(struct g_consumer *cp)
|
||||
KASSERT (cp->acr == 0, ("g_destroy_consumer with acr"));
|
||||
KASSERT (cp->acw == 0, ("g_destroy_consumer with acw"));
|
||||
KASSERT (cp->ace == 0, ("g_destroy_consumer with ace"));
|
||||
g_cancel_event(NULL, NULL, NULL, cp);
|
||||
g_cancel_event(cp);
|
||||
LIST_REMOVE(cp, consumer);
|
||||
devstat_remove_entry(cp->stat);
|
||||
g_free(cp);
|
||||
@ -193,7 +193,7 @@ g_new_providerf(struct g_geom *gp, const char *fmt, ...)
|
||||
DEVSTAT_TYPE_DIRECT, DEVSTAT_PRIORITY_MAX);
|
||||
LIST_INSERT_HEAD(&gp->provider, pp, provider);
|
||||
g_nproviders++;
|
||||
g_post_event(EV_NEW_PROVIDER, NULL, NULL, pp, NULL);
|
||||
g_post_event(EV_NEW_PROVIDER, pp, NULL);
|
||||
return (pp);
|
||||
}
|
||||
|
||||
@ -218,7 +218,7 @@ g_destroy_provider(struct g_provider *pp)
|
||||
KASSERT (pp->acr == 0, ("g_destroy_provider with acr"));
|
||||
KASSERT (pp->acw == 0, ("g_destroy_provider with acw"));
|
||||
KASSERT (pp->acw == 0, ("g_destroy_provider with ace"));
|
||||
g_cancel_event(NULL, NULL, pp, NULL);
|
||||
g_cancel_event(pp);
|
||||
g_nproviders--;
|
||||
LIST_REMOVE(pp, provider);
|
||||
gp = pp->geom;
|
||||
@ -447,7 +447,7 @@ g_access_rel(struct g_consumer *cp, int dcr, int dcw, int dce)
|
||||
g_spoil(pp, cp);
|
||||
else if (pp->acw != 0 && pp->acw == -dcw &&
|
||||
!(pp->geom->flags & G_GEOM_WITHER))
|
||||
g_post_event(EV_NEW_PROVIDER, NULL, NULL, pp, NULL);
|
||||
g_post_event(EV_NEW_PROVIDER, pp, NULL);
|
||||
|
||||
pp->acr += dcr;
|
||||
pp->acw += dcw;
|
||||
@ -567,7 +567,7 @@ g_spoil(struct g_provider *pp, struct g_consumer *cp)
|
||||
KASSERT(cp2->ace == 0, ("spoiling cp->ace = %d", cp2->ace));
|
||||
cp2->spoiled++;
|
||||
}
|
||||
g_post_event(EV_SPOILED, NULL, NULL, pp, cp);
|
||||
g_post_event(EV_SPOILED, pp, cp, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
|
Loading…
Reference in New Issue
Block a user