1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: gsnotify.c 8250 2007-09-25 13:31:24Z giles $ */
15 /* Notification machinery implementation */
16 #include "gx.h"
17 #include "gserrors.h"
18 #include "gsstruct.h"
19 #include "gsnotify.h"
20 
21 /* GC descriptors */
22 private_st_gs_notify_registration();
23 public_st_gs_notify_list();
24 
25 /* Initialize a notification list. */
26 void
gs_notify_init(gs_notify_list_t * nlist,gs_memory_t * mem)27 gs_notify_init(gs_notify_list_t *nlist, gs_memory_t *mem)
28 {
29     nlist->first = 0;
30     nlist->memory = mem;
31 }
32 
33 /* Register a client. */
34 int
gs_notify_register(gs_notify_list_t * nlist,gs_notify_proc_t proc,void * proc_data)35 gs_notify_register(gs_notify_list_t *nlist, gs_notify_proc_t proc,
36 		   void *proc_data)
37 {
38     gs_notify_registration_t *nreg =
39 	gs_alloc_struct(nlist->memory, gs_notify_registration_t,
40 			&st_gs_notify_registration, "gs_notify_register");
41 
42     if (nreg == 0)
43 	return_error(gs_error_VMerror);
44     nreg->proc = proc;
45     nreg->proc_data = proc_data;
46     nreg->next = nlist->first;
47     nlist->first = nreg;
48     return 0;
49 }
50 
51 /*
52  * Unregister a client.  Return 1 if the client was registered, 0 if not.
53  * If proc_data is 0, unregister all registrations of that proc; otherwise,
54  * unregister only the registration of that procedure with that proc_data.
55  */
56 static void
no_unreg_proc(void * pdata)57 no_unreg_proc(void *pdata)
58 {
59 }
60 int
gs_notify_unregister_calling(gs_notify_list_t * nlist,gs_notify_proc_t proc,void * proc_data,void (* unreg_proc)(void * pdata))61 gs_notify_unregister_calling(gs_notify_list_t *nlist, gs_notify_proc_t proc,
62 			     void *proc_data,
63 			     void (*unreg_proc)(void *pdata))
64 {
65     gs_notify_registration_t **prev = &nlist->first;
66     gs_notify_registration_t *cur;
67     bool found = 0;
68 
69     while ((cur = *prev) != 0)
70 	if (cur->proc == proc &&
71 	    (proc_data == 0 || cur->proc_data == proc_data)
72 	    ) {
73 	    *prev = cur->next;
74 	    unreg_proc(cur->proc_data);
75 	    gs_free_object(nlist->memory, cur, "gs_notify_unregister");
76 	    found = 1;
77 	} else
78 	    prev = &cur->next;
79     return found;
80 }
81 int
gs_notify_unregister(gs_notify_list_t * nlist,gs_notify_proc_t proc,void * proc_data)82 gs_notify_unregister(gs_notify_list_t *nlist, gs_notify_proc_t proc,
83 		     void *proc_data)
84 {
85     return gs_notify_unregister_calling(nlist, proc, proc_data, no_unreg_proc);
86 }
87 
88 /*
89  * Notify the clients on a list.  If an error occurs, return the first
90  * error code, but notify all clients regardless.
91  */
92 int
gs_notify_all(gs_notify_list_t * nlist,void * event_data)93 gs_notify_all(gs_notify_list_t *nlist, void *event_data)
94 {
95     gs_notify_registration_t *cur;
96     gs_notify_registration_t *next;
97     int ecode = 0;
98 
99     for (next = nlist->first; (cur = next) != 0;) {
100 	int code;
101 
102 	next = cur->next;
103 	code = cur->proc(cur->proc_data, event_data);
104 	if (code < 0 && ecode == 0)
105 	    ecode = code;
106     }
107     return ecode;
108 }
109 
110 /* Release a notification list. */
111 void
gs_notify_release(gs_notify_list_t * nlist)112 gs_notify_release(gs_notify_list_t *nlist)
113 {
114     gs_memory_t *mem = nlist->memory;
115 
116     while (nlist->first) {
117 	gs_notify_registration_t *next = nlist->first->next;
118 
119 	gs_free_object(mem, nlist->first, "gs_notify_release");
120 	nlist->first = next;
121     }
122 }
123