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