fb700 commited on
Commit
ea43bc6
1 Parent(s): 652cdeb

Upload 132 files

Browse files
.gitignore CHANGED
@@ -1,152 +1,152 @@
1
- # Byte-compiled / optimized / DLL files
2
- __pycache__/
3
- *.py[cod]
4
- *$py.class
5
-
6
- # C extensions
7
- *.so
8
-
9
- # Distribution / packaging
10
- .Python
11
- build/
12
- develop-eggs/
13
- dist/
14
- downloads/
15
- eggs/
16
- .eggs/
17
- lib/
18
- lib64/
19
- parts/
20
- sdist/
21
- var/
22
- wheels/
23
- pip-wheel-metadata/
24
- share/python-wheels/
25
- *.egg-info/
26
- .installed.cfg
27
- *.egg
28
- MANIFEST
29
-
30
- # PyInstaller
31
- # Usually these files are written by a python script from a template
32
- # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
- *.manifest
34
- *.spec
35
- # Installer logs
36
- pip-log.txt
37
- pip-delete-this-directory.txt
38
-
39
- # Unit test / coverage reports
40
- htmlcov/
41
- .tox/
42
- .nox/
43
- .coverage
44
- .coverage.*
45
- .cache
46
- nosetests.xml
47
- coverage.xml
48
- *.cover
49
- *.py,cover
50
- .hypothesis/
51
- .pytest_cache/
52
-
53
- # Translations
54
- *.mo
55
- *.pot
56
- github
57
- .github
58
- TEMP
59
- TRASH
60
-
61
- # Django stuff:
62
- *.log
63
- local_settings.py
64
- db.sqlite3
65
- db.sqlite3-journal
66
-
67
- # Flask stuff:
68
- instance/
69
- .webassets-cache
70
-
71
- # Scrapy stuff:
72
- .scrapy
73
-
74
- # Sphinx documentation
75
- docs/_build/
76
-
77
- # PyBuilder
78
- target/
79
-
80
- # Jupyter Notebook
81
- .ipynb_checkpoints
82
-
83
- # IPython
84
- profile_default/
85
- ipython_config.py
86
-
87
- # pyenv
88
- .python-version
89
-
90
- # pipenv
91
- # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
- # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
- # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
- # install all needed dependencies.
95
- #Pipfile.lock
96
-
97
- # PEP 582; used by e.g. github.com/David-OConnor/pyflow
98
- __pypackages__/
99
-
100
- # Celery stuff
101
- celerybeat-schedule
102
- celerybeat.pid
103
-
104
- # SageMath parsed files
105
- *.sage.py
106
-
107
- # Environments
108
- .env
109
- .venv
110
- env/
111
- venv/
112
- ENV/
113
- env.bak/
114
- venv.bak/
115
-
116
- # Spyder project settings
117
- .spyderproject
118
- .spyproject
119
-
120
- # Rope project settings
121
- .ropeproject
122
-
123
- # mkdocs documentation
124
- /site
125
-
126
- # mypy
127
- .mypy_cache/
128
- .dmypy.json
129
- dmypy.json
130
-
131
- # Pyre type checker
132
- .pyre/
133
-
134
- .vscode
135
- .idea
136
-
137
- history
138
- ssr_conf
139
- config_private.py
140
- gpt_log
141
- private.md
142
- private_upload
143
- other_llms
144
- cradle*
145
- debug*
146
- private*
147
- crazy_functions/test_project/pdf_and_word
148
- crazy_functions/test_samples
149
- request_llm/jittorllms
150
- multi-language
151
- request_llm/moss
152
- media
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ pip-wheel-metadata/
24
+ share/python-wheels/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+
53
+ # Translations
54
+ *.mo
55
+ *.pot
56
+ github
57
+ .github
58
+ TEMP
59
+ TRASH
60
+
61
+ # Django stuff:
62
+ *.log
63
+ local_settings.py
64
+ db.sqlite3
65
+ db.sqlite3-journal
66
+
67
+ # Flask stuff:
68
+ instance/
69
+ .webassets-cache
70
+
71
+ # Scrapy stuff:
72
+ .scrapy
73
+
74
+ # Sphinx documentation
75
+ docs/_build/
76
+
77
+ # PyBuilder
78
+ target/
79
+
80
+ # Jupyter Notebook
81
+ .ipynb_checkpoints
82
+
83
+ # IPython
84
+ profile_default/
85
+ ipython_config.py
86
+
87
+ # pyenv
88
+ .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
98
+ __pypackages__/
99
+
100
+ # Celery stuff
101
+ celerybeat-schedule
102
+ celerybeat.pid
103
+
104
+ # SageMath parsed files
105
+ *.sage.py
106
+
107
+ # Environments
108
+ .env
109
+ .venv
110
+ env/
111
+ venv/
112
+ ENV/
113
+ env.bak/
114
+ venv.bak/
115
+
116
+ # Spyder project settings
117
+ .spyderproject
118
+ .spyproject
119
+
120
+ # Rope project settings
121
+ .ropeproject
122
+
123
+ # mkdocs documentation
124
+ /site
125
+
126
+ # mypy
127
+ .mypy_cache/
128
+ .dmypy.json
129
+ dmypy.json
130
+
131
+ # Pyre type checker
132
+ .pyre/
133
+
134
+ .vscode
135
+ .idea
136
+
137
+ history
138
+ ssr_conf
139
+ config_private.py
140
+ gpt_log
141
+ private.md
142
+ private_upload
143
+ other_llms
144
+ cradle*
145
+ debug*
146
+ private*
147
+ crazy_functions/test_project/pdf_and_word
148
+ crazy_functions/test_samples
149
+ request_llm/jittorllms
150
+ multi-language
151
+ request_llm/moss
152
+ media
LICENSE CHANGED
@@ -1,674 +1,674 @@
1
- GNU GENERAL PUBLIC LICENSE
2
- Version 3, 29 June 2007
3
-
4
- Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
5
- Everyone is permitted to copy and distribute verbatim copies
6
- of this license document, but changing it is not allowed.
7
-
8
- Preamble
9
-
10
- The GNU General Public License is a free, copyleft license for
11
- software and other kinds of works.
12
-
13
- The licenses for most software and other practical works are designed
14
- to take away your freedom to share and change the works. By contrast,
15
- the GNU General Public License is intended to guarantee your freedom to
16
- share and change all versions of a program--to make sure it remains free
17
- software for all its users. We, the Free Software Foundation, use the
18
- GNU General Public License for most of our software; it applies also to
19
- any other work released this way by its authors. You can apply it to
20
- your programs, too.
21
-
22
- When we speak of free software, we are referring to freedom, not
23
- price. Our General Public Licenses are designed to make sure that you
24
- have the freedom to distribute copies of free software (and charge for
25
- them if you wish), that you receive source code or can get it if you
26
- want it, that you can change the software or use pieces of it in new
27
- free programs, and that you know you can do these things.
28
-
29
- To protect your rights, we need to prevent others from denying you
30
- these rights or asking you to surrender the rights. Therefore, you have
31
- certain responsibilities if you distribute copies of the software, or if
32
- you modify it: responsibilities to respect the freedom of others.
33
-
34
- For example, if you distribute copies of such a program, whether
35
- gratis or for a fee, you must pass on to the recipients the same
36
- freedoms that you received. You must make sure that they, too, receive
37
- or can get the source code. And you must show them these terms so they
38
- know their rights.
39
-
40
- Developers that use the GNU GPL protect your rights with two steps:
41
- (1) assert copyright on the software, and (2) offer you this License
42
- giving you legal permission to copy, distribute and/or modify it.
43
-
44
- For the developers' and authors' protection, the GPL clearly explains
45
- that there is no warranty for this free software. For both users' and
46
- authors' sake, the GPL requires that modified versions be marked as
47
- changed, so that their problems will not be attributed erroneously to
48
- authors of previous versions.
49
-
50
- Some devices are designed to deny users access to install or run
51
- modified versions of the software inside them, although the manufacturer
52
- can do so. This is fundamentally incompatible with the aim of
53
- protecting users' freedom to change the software. The systematic
54
- pattern of such abuse occurs in the area of products for individuals to
55
- use, which is precisely where it is most unacceptable. Therefore, we
56
- have designed this version of the GPL to prohibit the practice for those
57
- products. If such problems arise substantially in other domains, we
58
- stand ready to extend this provision to those domains in future versions
59
- of the GPL, as needed to protect the freedom of users.
60
-
61
- Finally, every program is threatened constantly by software patents.
62
- States should not allow patents to restrict development and use of
63
- software on general-purpose computers, but in those that do, we wish to
64
- avoid the special danger that patents applied to a free program could
65
- make it effectively proprietary. To prevent this, the GPL assures that
66
- patents cannot be used to render the program non-free.
67
-
68
- The precise terms and conditions for copying, distribution and
69
- modification follow.
70
-
71
- TERMS AND CONDITIONS
72
-
73
- 0. Definitions.
74
-
75
- "This License" refers to version 3 of the GNU General Public License.
76
-
77
- "Copyright" also means copyright-like laws that apply to other kinds of
78
- works, such as semiconductor masks.
79
-
80
- "The Program" refers to any copyrightable work licensed under this
81
- License. Each licensee is addressed as "you". "Licensees" and
82
- "recipients" may be individuals or organizations.
83
-
84
- To "modify" a work means to copy from or adapt all or part of the work
85
- in a fashion requiring copyright permission, other than the making of an
86
- exact copy. The resulting work is called a "modified version" of the
87
- earlier work or a work "based on" the earlier work.
88
-
89
- A "covered work" means either the unmodified Program or a work based
90
- on the Program.
91
-
92
- To "propagate" a work means to do anything with it that, without
93
- permission, would make you directly or secondarily liable for
94
- infringement under applicable copyright law, except executing it on a
95
- computer or modifying a private copy. Propagation includes copying,
96
- distribution (with or without modification), making available to the
97
- public, and in some countries other activities as well.
98
-
99
- To "convey" a work means any kind of propagation that enables other
100
- parties to make or receive copies. Mere interaction with a user through
101
- a computer network, with no transfer of a copy, is not conveying.
102
-
103
- An interactive user interface displays "Appropriate Legal Notices"
104
- to the extent that it includes a convenient and prominently visible
105
- feature that (1) displays an appropriate copyright notice, and (2)
106
- tells the user that there is no warranty for the work (except to the
107
- extent that warranties are provided), that licensees may convey the
108
- work under this License, and how to view a copy of this License. If
109
- the interface presents a list of user commands or options, such as a
110
- menu, a prominent item in the list meets this criterion.
111
-
112
- 1. Source Code.
113
-
114
- The "source code" for a work means the preferred form of the work
115
- for making modifications to it. "Object code" means any non-source
116
- form of a work.
117
-
118
- A "Standard Interface" means an interface that either is an official
119
- standard defined by a recognized standards body, or, in the case of
120
- interfaces specified for a particular programming language, one that
121
- is widely used among developers working in that language.
122
-
123
- The "System Libraries" of an executable work include anything, other
124
- than the work as a whole, that (a) is included in the normal form of
125
- packaging a Major Component, but which is not part of that Major
126
- Component, and (b) serves only to enable use of the work with that
127
- Major Component, or to implement a Standard Interface for which an
128
- implementation is available to the public in source code form. A
129
- "Major Component", in this context, means a major essential component
130
- (kernel, window system, and so on) of the specific operating system
131
- (if any) on which the executable work runs, or a compiler used to
132
- produce the work, or an object code interpreter used to run it.
133
-
134
- The "Corresponding Source" for a work in object code form means all
135
- the source code needed to generate, install, and (for an executable
136
- work) run the object code and to modify the work, including scripts to
137
- control those activities. However, it does not include the work's
138
- System Libraries, or general-purpose tools or generally available free
139
- programs which are used unmodified in performing those activities but
140
- which are not part of the work. For example, Corresponding Source
141
- includes interface definition files associated with source files for
142
- the work, and the source code for shared libraries and dynamically
143
- linked subprograms that the work is specifically designed to require,
144
- such as by intimate data communication or control flow between those
145
- subprograms and other parts of the work.
146
-
147
- The Corresponding Source need not include anything that users
148
- can regenerate automatically from other parts of the Corresponding
149
- Source.
150
-
151
- The Corresponding Source for a work in source code form is that
152
- same work.
153
-
154
- 2. Basic Permissions.
155
-
156
- All rights granted under this License are granted for the term of
157
- copyright on the Program, and are irrevocable provided the stated
158
- conditions are met. This License explicitly affirms your unlimited
159
- permission to run the unmodified Program. The output from running a
160
- covered work is covered by this License only if the output, given its
161
- content, constitutes a covered work. This License acknowledges your
162
- rights of fair use or other equivalent, as provided by copyright law.
163
-
164
- You may make, run and propagate covered works that you do not
165
- convey, without conditions so long as your license otherwise remains
166
- in force. You may convey covered works to others for the sole purpose
167
- of having them make modifications exclusively for you, or provide you
168
- with facilities for running those works, provided that you comply with
169
- the terms of this License in conveying all material for which you do
170
- not control copyright. Those thus making or running the covered works
171
- for you must do so exclusively on your behalf, under your direction
172
- and control, on terms that prohibit them from making any copies of
173
- your copyrighted material outside their relationship with you.
174
-
175
- Conveying under any other circumstances is permitted solely under
176
- the conditions stated below. Sublicensing is not allowed; section 10
177
- makes it unnecessary.
178
-
179
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180
-
181
- No covered work shall be deemed part of an effective technological
182
- measure under any applicable law fulfilling obligations under article
183
- 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184
- similar laws prohibiting or restricting circumvention of such
185
- measures.
186
-
187
- When you convey a covered work, you waive any legal power to forbid
188
- circumvention of technological measures to the extent such circumvention
189
- is effected by exercising rights under this License with respect to
190
- the covered work, and you disclaim any intention to limit operation or
191
- modification of the work as a means of enforcing, against the work's
192
- users, your or third parties' legal rights to forbid circumvention of
193
- technological measures.
194
-
195
- 4. Conveying Verbatim Copies.
196
-
197
- You may convey verbatim copies of the Program's source code as you
198
- receive it, in any medium, provided that you conspicuously and
199
- appropriately publish on each copy an appropriate copyright notice;
200
- keep intact all notices stating that this License and any
201
- non-permissive terms added in accord with section 7 apply to the code;
202
- keep intact all notices of the absence of any warranty; and give all
203
- recipients a copy of this License along with the Program.
204
-
205
- You may charge any price or no price for each copy that you convey,
206
- and you may offer support or warranty protection for a fee.
207
-
208
- 5. Conveying Modified Source Versions.
209
-
210
- You may convey a work based on the Program, or the modifications to
211
- produce it from the Program, in the form of source code under the
212
- terms of section 4, provided that you also meet all of these conditions:
213
-
214
- a) The work must carry prominent notices stating that you modified
215
- it, and giving a relevant date.
216
-
217
- b) The work must carry prominent notices stating that it is
218
- released under this License and any conditions added under section
219
- 7. This requirement modifies the requirement in section 4 to
220
- "keep intact all notices".
221
-
222
- c) You must license the entire work, as a whole, under this
223
- License to anyone who comes into possession of a copy. This
224
- License will therefore apply, along with any applicable section 7
225
- additional terms, to the whole of the work, and all its parts,
226
- regardless of how they are packaged. This License gives no
227
- permission to license the work in any other way, but it does not
228
- invalidate such permission if you have separately received it.
229
-
230
- d) If the work has interactive user interfaces, each must display
231
- Appropriate Legal Notices; however, if the Program has interactive
232
- interfaces that do not display Appropriate Legal Notices, your
233
- work need not make them do so.
234
-
235
- A compilation of a covered work with other separate and independent
236
- works, which are not by their nature extensions of the covered work,
237
- and which are not combined with it such as to form a larger program,
238
- in or on a volume of a storage or distribution medium, is called an
239
- "aggregate" if the compilation and its resulting copyright are not
240
- used to limit the access or legal rights of the compilation's users
241
- beyond what the individual works permit. Inclusion of a covered work
242
- in an aggregate does not cause this License to apply to the other
243
- parts of the aggregate.
244
-
245
- 6. Conveying Non-Source Forms.
246
-
247
- You may convey a covered work in object code form under the terms
248
- of sections 4 and 5, provided that you also convey the
249
- machine-readable Corresponding Source under the terms of this License,
250
- in one of these ways:
251
-
252
- a) Convey the object code in, or embodied in, a physical product
253
- (including a physical distribution medium), accompanied by the
254
- Corresponding Source fixed on a durable physical medium
255
- customarily used for software interchange.
256
-
257
- b) Convey the object code in, or embodied in, a physical product
258
- (including a physical distribution medium), accompanied by a
259
- written offer, valid for at least three years and valid for as
260
- long as you offer spare parts or customer support for that product
261
- model, to give anyone who possesses the object code either (1) a
262
- copy of the Corresponding Source for all the software in the
263
- product that is covered by this License, on a durable physical
264
- medium customarily used for software interchange, for a price no
265
- more than your reasonable cost of physically performing this
266
- conveying of source, or (2) access to copy the
267
- Corresponding Source from a network server at no charge.
268
-
269
- c) Convey individual copies of the object code with a copy of the
270
- written offer to provide the Corresponding Source. This
271
- alternative is allowed only occasionally and noncommercially, and
272
- only if you received the object code with such an offer, in accord
273
- with subsection 6b.
274
-
275
- d) Convey the object code by offering access from a designated
276
- place (gratis or for a charge), and offer equivalent access to the
277
- Corresponding Source in the same way through the same place at no
278
- further charge. You need not require recipients to copy the
279
- Corresponding Source along with the object code. If the place to
280
- copy the object code is a network server, the Corresponding Source
281
- may be on a different server (operated by you or a third party)
282
- that supports equivalent copying facilities, provided you maintain
283
- clear directions next to the object code saying where to find the
284
- Corresponding Source. Regardless of what server hosts the
285
- Corresponding Source, you remain obligated to ensure that it is
286
- available for as long as needed to satisfy these requirements.
287
-
288
- e) Convey the object code using peer-to-peer transmission, provided
289
- you inform other peers where the object code and Corresponding
290
- Source of the work are being offered to the general public at no
291
- charge under subsection 6d.
292
-
293
- A separable portion of the object code, whose source code is excluded
294
- from the Corresponding Source as a System Library, need not be
295
- included in conveying the object code work.
296
-
297
- A "User Product" is either (1) a "consumer product", which means any
298
- tangible personal property which is normally used for personal, family,
299
- or household purposes, or (2) anything designed or sold for incorporation
300
- into a dwelling. In determining whether a product is a consumer product,
301
- doubtful cases shall be resolved in favor of coverage. For a particular
302
- product received by a particular user, "normally used" refers to a
303
- typical or common use of that class of product, regardless of the status
304
- of the particular user or of the way in which the particular user
305
- actually uses, or expects or is expected to use, the product. A product
306
- is a consumer product regardless of whether the product has substantial
307
- commercial, industrial or non-consumer uses, unless such uses represent
308
- the only significant mode of use of the product.
309
-
310
- "Installation Information" for a User Product means any methods,
311
- procedures, authorization keys, or other information required to install
312
- and execute modified versions of a covered work in that User Product from
313
- a modified version of its Corresponding Source. The information must
314
- suffice to ensure that the continued functioning of the modified object
315
- code is in no case prevented or interfered with solely because
316
- modification has been made.
317
-
318
- If you convey an object code work under this section in, or with, or
319
- specifically for use in, a User Product, and the conveying occurs as
320
- part of a transaction in which the right of possession and use of the
321
- User Product is transferred to the recipient in perpetuity or for a
322
- fixed term (regardless of how the transaction is characterized), the
323
- Corresponding Source conveyed under this section must be accompanied
324
- by the Installation Information. But this requirement does not apply
325
- if neither you nor any third party retains the ability to install
326
- modified object code on the User Product (for example, the work has
327
- been installed in ROM).
328
-
329
- The requirement to provide Installation Information does not include a
330
- requirement to continue to provide support service, warranty, or updates
331
- for a work that has been modified or installed by the recipient, or for
332
- the User Product in which it has been modified or installed. Access to a
333
- network may be denied when the modification itself materially and
334
- adversely affects the operation of the network or violates the rules and
335
- protocols for communication across the network.
336
-
337
- Corresponding Source conveyed, and Installation Information provided,
338
- in accord with this section must be in a format that is publicly
339
- documented (and with an implementation available to the public in
340
- source code form), and must require no special password or key for
341
- unpacking, reading or copying.
342
-
343
- 7. Additional Terms.
344
-
345
- "Additional permissions" are terms that supplement the terms of this
346
- License by making exceptions from one or more of its conditions.
347
- Additional permissions that are applicable to the entire Program shall
348
- be treated as though they were included in this License, to the extent
349
- that they are valid under applicable law. If additional permissions
350
- apply only to part of the Program, that part may be used separately
351
- under those permissions, but the entire Program remains governed by
352
- this License without regard to the additional permissions.
353
-
354
- When you convey a copy of a covered work, you may at your option
355
- remove any additional permissions from that copy, or from any part of
356
- it. (Additional permissions may be written to require their own
357
- removal in certain cases when you modify the work.) You may place
358
- additional permissions on material, added by you to a covered work,
359
- for which you have or can give appropriate copyright permission.
360
-
361
- Notwithstanding any other provision of this License, for material you
362
- add to a covered work, you may (if authorized by the copyright holders of
363
- that material) supplement the terms of this License with terms:
364
-
365
- a) Disclaiming warranty or limiting liability differently from the
366
- terms of sections 15 and 16 of this License; or
367
-
368
- b) Requiring preservation of specified reasonable legal notices or
369
- author attributions in that material or in the Appropriate Legal
370
- Notices displayed by works containing it; or
371
-
372
- c) Prohibiting misrepresentation of the origin of that material, or
373
- requiring that modified versions of such material be marked in
374
- reasonable ways as different from the original version; or
375
-
376
- d) Limiting the use for publicity purposes of names of licensors or
377
- authors of the material; or
378
-
379
- e) Declining to grant rights under trademark law for use of some
380
- trade names, trademarks, or service marks; or
381
-
382
- f) Requiring indemnification of licensors and authors of that
383
- material by anyone who conveys the material (or modified versions of
384
- it) with contractual assumptions of liability to the recipient, for
385
- any liability that these contractual assumptions directly impose on
386
- those licensors and authors.
387
-
388
- All other non-permissive additional terms are considered "further
389
- restrictions" within the meaning of section 10. If the Program as you
390
- received it, or any part of it, contains a notice stating that it is
391
- governed by this License along with a term that is a further
392
- restriction, you may remove that term. If a license document contains
393
- a further restriction but permits relicensing or conveying under this
394
- License, you may add to a covered work material governed by the terms
395
- of that license document, provided that the further restriction does
396
- not survive such relicensing or conveying.
397
-
398
- If you add terms to a covered work in accord with this section, you
399
- must place, in the relevant source files, a statement of the
400
- additional terms that apply to those files, or a notice indicating
401
- where to find the applicable terms.
402
-
403
- Additional terms, permissive or non-permissive, may be stated in the
404
- form of a separately written license, or stated as exceptions;
405
- the above requirements apply either way.
406
-
407
- 8. Termination.
408
-
409
- You may not propagate or modify a covered work except as expressly
410
- provided under this License. Any attempt otherwise to propagate or
411
- modify it is void, and will automatically terminate your rights under
412
- this License (including any patent licenses granted under the third
413
- paragraph of section 11).
414
-
415
- However, if you cease all violation of this License, then your
416
- license from a particular copyright holder is reinstated (a)
417
- provisionally, unless and until the copyright holder explicitly and
418
- finally terminates your license, and (b) permanently, if the copyright
419
- holder fails to notify you of the violation by some reasonable means
420
- prior to 60 days after the cessation.
421
-
422
- Moreover, your license from a particular copyright holder is
423
- reinstated permanently if the copyright holder notifies you of the
424
- violation by some reasonable means, this is the first time you have
425
- received notice of violation of this License (for any work) from that
426
- copyright holder, and you cure the violation prior to 30 days after
427
- your receipt of the notice.
428
-
429
- Termination of your rights under this section does not terminate the
430
- licenses of parties who have received copies or rights from you under
431
- this License. If your rights have been terminated and not permanently
432
- reinstated, you do not qualify to receive new licenses for the same
433
- material under section 10.
434
-
435
- 9. Acceptance Not Required for Having Copies.
436
-
437
- You are not required to accept this License in order to receive or
438
- run a copy of the Program. Ancillary propagation of a covered work
439
- occurring solely as a consequence of using peer-to-peer transmission
440
- to receive a copy likewise does not require acceptance. However,
441
- nothing other than this License grants you permission to propagate or
442
- modify any covered work. These actions infringe copyright if you do
443
- not accept this License. Therefore, by modifying or propagating a
444
- covered work, you indicate your acceptance of this License to do so.
445
-
446
- 10. Automatic Licensing of Downstream Recipients.
447
-
448
- Each time you convey a covered work, the recipient automatically
449
- receives a license from the original licensors, to run, modify and
450
- propagate that work, subject to this License. You are not responsible
451
- for enforcing compliance by third parties with this License.
452
-
453
- An "entity transaction" is a transaction transferring control of an
454
- organization, or substantially all assets of one, or subdividing an
455
- organization, or merging organizations. If propagation of a covered
456
- work results from an entity transaction, each party to that
457
- transaction who receives a copy of the work also receives whatever
458
- licenses to the work the party's predecessor in interest had or could
459
- give under the previous paragraph, plus a right to possession of the
460
- Corresponding Source of the work from the predecessor in interest, if
461
- the predecessor has it or can get it with reasonable efforts.
462
-
463
- You may not impose any further restrictions on the exercise of the
464
- rights granted or affirmed under this License. For example, you may
465
- not impose a license fee, royalty, or other charge for exercise of
466
- rights granted under this License, and you may not initiate litigation
467
- (including a cross-claim or counterclaim in a lawsuit) alleging that
468
- any patent claim is infringed by making, using, selling, offering for
469
- sale, or importing the Program or any portion of it.
470
-
471
- 11. Patents.
472
-
473
- A "contributor" is a copyright holder who authorizes use under this
474
- License of the Program or a work on which the Program is based. The
475
- work thus licensed is called the contributor's "contributor version".
476
-
477
- A contributor's "essential patent claims" are all patent claims
478
- owned or controlled by the contributor, whether already acquired or
479
- hereafter acquired, that would be infringed by some manner, permitted
480
- by this License, of making, using, or selling its contributor version,
481
- but do not include claims that would be infringed only as a
482
- consequence of further modification of the contributor version. For
483
- purposes of this definition, "control" includes the right to grant
484
- patent sublicenses in a manner consistent with the requirements of
485
- this License.
486
-
487
- Each contributor grants you a non-exclusive, worldwide, royalty-free
488
- patent license under the contributor's essential patent claims, to
489
- make, use, sell, offer for sale, import and otherwise run, modify and
490
- propagate the contents of its contributor version.
491
-
492
- In the following three paragraphs, a "patent license" is any express
493
- agreement or commitment, however denominated, not to enforce a patent
494
- (such as an express permission to practice a patent or covenant not to
495
- sue for patent infringement). To "grant" such a patent license to a
496
- party means to make such an agreement or commitment not to enforce a
497
- patent against the party.
498
-
499
- If you convey a covered work, knowingly relying on a patent license,
500
- and the Corresponding Source of the work is not available for anyone
501
- to copy, free of charge and under the terms of this License, through a
502
- publicly available network server or other readily accessible means,
503
- then you must either (1) cause the Corresponding Source to be so
504
- available, or (2) arrange to deprive yourself of the benefit of the
505
- patent license for this particular work, or (3) arrange, in a manner
506
- consistent with the requirements of this License, to extend the patent
507
- license to downstream recipients. "Knowingly relying" means you have
508
- actual knowledge that, but for the patent license, your conveying the
509
- covered work in a country, or your recipient's use of the covered work
510
- in a country, would infringe one or more identifiable patents in that
511
- country that you have reason to believe are valid.
512
-
513
- If, pursuant to or in connection with a single transaction or
514
- arrangement, you convey, or propagate by procuring conveyance of, a
515
- covered work, and grant a patent license to some of the parties
516
- receiving the covered work authorizing them to use, propagate, modify
517
- or convey a specific copy of the covered work, then the patent license
518
- you grant is automatically extended to all recipients of the covered
519
- work and works based on it.
520
-
521
- A patent license is "discriminatory" if it does not include within
522
- the scope of its coverage, prohibits the exercise of, or is
523
- conditioned on the non-exercise of one or more of the rights that are
524
- specifically granted under this License. You may not convey a covered
525
- work if you are a party to an arrangement with a third party that is
526
- in the business of distributing software, under which you make payment
527
- to the third party based on the extent of your activity of conveying
528
- the work, and under which the third party grants, to any of the
529
- parties who would receive the covered work from you, a discriminatory
530
- patent license (a) in connection with copies of the covered work
531
- conveyed by you (or copies made from those copies), or (b) primarily
532
- for and in connection with specific products or compilations that
533
- contain the covered work, unless you entered into that arrangement,
534
- or that patent license was granted, prior to 28 March 2007.
535
-
536
- Nothing in this License shall be construed as excluding or limiting
537
- any implied license or other defenses to infringement that may
538
- otherwise be available to you under applicable patent law.
539
-
540
- 12. No Surrender of Others' Freedom.
541
-
542
- If conditions are imposed on you (whether by court order, agreement or
543
- otherwise) that contradict the conditions of this License, they do not
544
- excuse you from the conditions of this License. If you cannot convey a
545
- covered work so as to satisfy simultaneously your obligations under this
546
- License and any other pertinent obligations, then as a consequence you may
547
- not convey it at all. For example, if you agree to terms that obligate you
548
- to collect a royalty for further conveying from those to whom you convey
549
- the Program, the only way you could satisfy both those terms and this
550
- License would be to refrain entirely from conveying the Program.
551
-
552
- 13. Use with the GNU Affero General Public License.
553
-
554
- Notwithstanding any other provision of this License, you have
555
- permission to link or combine any covered work with a work licensed
556
- under version 3 of the GNU Affero General Public License into a single
557
- combined work, and to convey the resulting work. The terms of this
558
- License will continue to apply to the part which is the covered work,
559
- but the special requirements of the GNU Affero General Public License,
560
- section 13, concerning interaction through a network will apply to the
561
- combination as such.
562
-
563
- 14. Revised Versions of this License.
564
-
565
- The Free Software Foundation may publish revised and/or new versions of
566
- the GNU General Public License from time to time. Such new versions will
567
- be similar in spirit to the present version, but may differ in detail to
568
- address new problems or concerns.
569
-
570
- Each version is given a distinguishing version number. If the
571
- Program specifies that a certain numbered version of the GNU General
572
- Public License "or any later version" applies to it, you have the
573
- option of following the terms and conditions either of that numbered
574
- version or of any later version published by the Free Software
575
- Foundation. If the Program does not specify a version number of the
576
- GNU General Public License, you may choose any version ever published
577
- by the Free Software Foundation.
578
-
579
- If the Program specifies that a proxy can decide which future
580
- versions of the GNU General Public License can be used, that proxy's
581
- public statement of acceptance of a version permanently authorizes you
582
- to choose that version for the Program.
583
-
584
- Later license versions may give you additional or different
585
- permissions. However, no additional obligations are imposed on any
586
- author or copyright holder as a result of your choosing to follow a
587
- later version.
588
-
589
- 15. Disclaimer of Warranty.
590
-
591
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592
- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593
- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594
- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595
- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596
- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597
- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598
- ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599
-
600
- 16. Limitation of Liability.
601
-
602
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603
- WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604
- THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605
- GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606
- USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607
- DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608
- PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609
- EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610
- SUCH DAMAGES.
611
-
612
- 17. Interpretation of Sections 15 and 16.
613
-
614
- If the disclaimer of warranty and limitation of liability provided
615
- above cannot be given local legal effect according to their terms,
616
- reviewing courts shall apply local law that most closely approximates
617
- an absolute waiver of all civil liability in connection with the
618
- Program, unless a warranty or assumption of liability accompanies a
619
- copy of the Program in return for a fee.
620
-
621
- END OF TERMS AND CONDITIONS
622
-
623
- How to Apply These Terms to Your New Programs
624
-
625
- If you develop a new program, and you want it to be of the greatest
626
- possible use to the public, the best way to achieve this is to make it
627
- free software which everyone can redistribute and change under these terms.
628
-
629
- To do so, attach the following notices to the program. It is safest
630
- to attach them to the start of each source file to most effectively
631
- state the exclusion of warranty; and each file should have at least
632
- the "copyright" line and a pointer to where the full notice is found.
633
-
634
- <one line to give the program's name and a brief idea of what it does.>
635
- Copyright (C) <year> <name of author>
636
-
637
- This program is free software: you can redistribute it and/or modify
638
- it under the terms of the GNU General Public License as published by
639
- the Free Software Foundation, either version 3 of the License, or
640
- (at your option) any later version.
641
-
642
- This program is distributed in the hope that it will be useful,
643
- but WITHOUT ANY WARRANTY; without even the implied warranty of
644
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645
- GNU General Public License for more details.
646
-
647
- You should have received a copy of the GNU General Public License
648
- along with this program. If not, see <https://www.gnu.org/licenses/>.
649
-
650
- Also add information on how to contact you by electronic and paper mail.
651
-
652
- If the program does terminal interaction, make it output a short
653
- notice like this when it starts in an interactive mode:
654
-
655
- <program> Copyright (C) <year> <name of author>
656
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657
- This is free software, and you are welcome to redistribute it
658
- under certain conditions; type `show c' for details.
659
-
660
- The hypothetical commands `show w' and `show c' should show the appropriate
661
- parts of the General Public License. Of course, your program's commands
662
- might be different; for a GUI interface, you would use an "about box".
663
-
664
- You should also get your employer (if you work as a programmer) or school,
665
- if any, to sign a "copyright disclaimer" for the program, if necessary.
666
- For more information on this, and how to apply and follow the GNU GPL, see
667
- <https://www.gnu.org/licenses/>.
668
-
669
- The GNU General Public License does not permit incorporating your program
670
- into proprietary programs. If your program is a subroutine library, you
671
- may consider it more useful to permit linking proprietary applications with
672
- the library. If this is what you want to do, use the GNU Lesser General
673
- Public License instead of this License. But first, please read
674
- <https://www.gnu.org/licenses/why-not-lgpl.html>.
 
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+ Preamble
9
+
10
+ The GNU General Public License is a free, copyleft license for
11
+ software and other kinds of works.
12
+
13
+ The licenses for most software and other practical works are designed
14
+ to take away your freedom to share and change the works. By contrast,
15
+ the GNU General Public License is intended to guarantee your freedom to
16
+ share and change all versions of a program--to make sure it remains free
17
+ software for all its users. We, the Free Software Foundation, use the
18
+ GNU General Public License for most of our software; it applies also to
19
+ any other work released this way by its authors. You can apply it to
20
+ your programs, too.
21
+
22
+ When we speak of free software, we are referring to freedom, not
23
+ price. Our General Public Licenses are designed to make sure that you
24
+ have the freedom to distribute copies of free software (and charge for
25
+ them if you wish), that you receive source code or can get it if you
26
+ want it, that you can change the software or use pieces of it in new
27
+ free programs, and that you know you can do these things.
28
+
29
+ To protect your rights, we need to prevent others from denying you
30
+ these rights or asking you to surrender the rights. Therefore, you have
31
+ certain responsibilities if you distribute copies of the software, or if
32
+ you modify it: responsibilities to respect the freedom of others.
33
+
34
+ For example, if you distribute copies of such a program, whether
35
+ gratis or for a fee, you must pass on to the recipients the same
36
+ freedoms that you received. You must make sure that they, too, receive
37
+ or can get the source code. And you must show them these terms so they
38
+ know their rights.
39
+
40
+ Developers that use the GNU GPL protect your rights with two steps:
41
+ (1) assert copyright on the software, and (2) offer you this License
42
+ giving you legal permission to copy, distribute and/or modify it.
43
+
44
+ For the developers' and authors' protection, the GPL clearly explains
45
+ that there is no warranty for this free software. For both users' and
46
+ authors' sake, the GPL requires that modified versions be marked as
47
+ changed, so that their problems will not be attributed erroneously to
48
+ authors of previous versions.
49
+
50
+ Some devices are designed to deny users access to install or run
51
+ modified versions of the software inside them, although the manufacturer
52
+ can do so. This is fundamentally incompatible with the aim of
53
+ protecting users' freedom to change the software. The systematic
54
+ pattern of such abuse occurs in the area of products for individuals to
55
+ use, which is precisely where it is most unacceptable. Therefore, we
56
+ have designed this version of the GPL to prohibit the practice for those
57
+ products. If such problems arise substantially in other domains, we
58
+ stand ready to extend this provision to those domains in future versions
59
+ of the GPL, as needed to protect the freedom of users.
60
+
61
+ Finally, every program is threatened constantly by software patents.
62
+ States should not allow patents to restrict development and use of
63
+ software on general-purpose computers, but in those that do, we wish to
64
+ avoid the special danger that patents applied to a free program could
65
+ make it effectively proprietary. To prevent this, the GPL assures that
66
+ patents cannot be used to render the program non-free.
67
+
68
+ The precise terms and conditions for copying, distribution and
69
+ modification follow.
70
+
71
+ TERMS AND CONDITIONS
72
+
73
+ 0. Definitions.
74
+
75
+ "This License" refers to version 3 of the GNU General Public License.
76
+
77
+ "Copyright" also means copyright-like laws that apply to other kinds of
78
+ works, such as semiconductor masks.
79
+
80
+ "The Program" refers to any copyrightable work licensed under this
81
+ License. Each licensee is addressed as "you". "Licensees" and
82
+ "recipients" may be individuals or organizations.
83
+
84
+ To "modify" a work means to copy from or adapt all or part of the work
85
+ in a fashion requiring copyright permission, other than the making of an
86
+ exact copy. The resulting work is called a "modified version" of the
87
+ earlier work or a work "based on" the earlier work.
88
+
89
+ A "covered work" means either the unmodified Program or a work based
90
+ on the Program.
91
+
92
+ To "propagate" a work means to do anything with it that, without
93
+ permission, would make you directly or secondarily liable for
94
+ infringement under applicable copyright law, except executing it on a
95
+ computer or modifying a private copy. Propagation includes copying,
96
+ distribution (with or without modification), making available to the
97
+ public, and in some countries other activities as well.
98
+
99
+ To "convey" a work means any kind of propagation that enables other
100
+ parties to make or receive copies. Mere interaction with a user through
101
+ a computer network, with no transfer of a copy, is not conveying.
102
+
103
+ An interactive user interface displays "Appropriate Legal Notices"
104
+ to the extent that it includes a convenient and prominently visible
105
+ feature that (1) displays an appropriate copyright notice, and (2)
106
+ tells the user that there is no warranty for the work (except to the
107
+ extent that warranties are provided), that licensees may convey the
108
+ work under this License, and how to view a copy of this License. If
109
+ the interface presents a list of user commands or options, such as a
110
+ menu, a prominent item in the list meets this criterion.
111
+
112
+ 1. Source Code.
113
+
114
+ The "source code" for a work means the preferred form of the work
115
+ for making modifications to it. "Object code" means any non-source
116
+ form of a work.
117
+
118
+ A "Standard Interface" means an interface that either is an official
119
+ standard defined by a recognized standards body, or, in the case of
120
+ interfaces specified for a particular programming language, one that
121
+ is widely used among developers working in that language.
122
+
123
+ The "System Libraries" of an executable work include anything, other
124
+ than the work as a whole, that (a) is included in the normal form of
125
+ packaging a Major Component, but which is not part of that Major
126
+ Component, and (b) serves only to enable use of the work with that
127
+ Major Component, or to implement a Standard Interface for which an
128
+ implementation is available to the public in source code form. A
129
+ "Major Component", in this context, means a major essential component
130
+ (kernel, window system, and so on) of the specific operating system
131
+ (if any) on which the executable work runs, or a compiler used to
132
+ produce the work, or an object code interpreter used to run it.
133
+
134
+ The "Corresponding Source" for a work in object code form means all
135
+ the source code needed to generate, install, and (for an executable
136
+ work) run the object code and to modify the work, including scripts to
137
+ control those activities. However, it does not include the work's
138
+ System Libraries, or general-purpose tools or generally available free
139
+ programs which are used unmodified in performing those activities but
140
+ which are not part of the work. For example, Corresponding Source
141
+ includes interface definition files associated with source files for
142
+ the work, and the source code for shared libraries and dynamically
143
+ linked subprograms that the work is specifically designed to require,
144
+ such as by intimate data communication or control flow between those
145
+ subprograms and other parts of the work.
146
+
147
+ The Corresponding Source need not include anything that users
148
+ can regenerate automatically from other parts of the Corresponding
149
+ Source.
150
+
151
+ The Corresponding Source for a work in source code form is that
152
+ same work.
153
+
154
+ 2. Basic Permissions.
155
+
156
+ All rights granted under this License are granted for the term of
157
+ copyright on the Program, and are irrevocable provided the stated
158
+ conditions are met. This License explicitly affirms your unlimited
159
+ permission to run the unmodified Program. The output from running a
160
+ covered work is covered by this License only if the output, given its
161
+ content, constitutes a covered work. This License acknowledges your
162
+ rights of fair use or other equivalent, as provided by copyright law.
163
+
164
+ You may make, run and propagate covered works that you do not
165
+ convey, without conditions so long as your license otherwise remains
166
+ in force. You may convey covered works to others for the sole purpose
167
+ of having them make modifications exclusively for you, or provide you
168
+ with facilities for running those works, provided that you comply with
169
+ the terms of this License in conveying all material for which you do
170
+ not control copyright. Those thus making or running the covered works
171
+ for you must do so exclusively on your behalf, under your direction
172
+ and control, on terms that prohibit them from making any copies of
173
+ your copyrighted material outside their relationship with you.
174
+
175
+ Conveying under any other circumstances is permitted solely under
176
+ the conditions stated below. Sublicensing is not allowed; section 10
177
+ makes it unnecessary.
178
+
179
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180
+
181
+ No covered work shall be deemed part of an effective technological
182
+ measure under any applicable law fulfilling obligations under article
183
+ 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184
+ similar laws prohibiting or restricting circumvention of such
185
+ measures.
186
+
187
+ When you convey a covered work, you waive any legal power to forbid
188
+ circumvention of technological measures to the extent such circumvention
189
+ is effected by exercising rights under this License with respect to
190
+ the covered work, and you disclaim any intention to limit operation or
191
+ modification of the work as a means of enforcing, against the work's
192
+ users, your or third parties' legal rights to forbid circumvention of
193
+ technological measures.
194
+
195
+ 4. Conveying Verbatim Copies.
196
+
197
+ You may convey verbatim copies of the Program's source code as you
198
+ receive it, in any medium, provided that you conspicuously and
199
+ appropriately publish on each copy an appropriate copyright notice;
200
+ keep intact all notices stating that this License and any
201
+ non-permissive terms added in accord with section 7 apply to the code;
202
+ keep intact all notices of the absence of any warranty; and give all
203
+ recipients a copy of this License along with the Program.
204
+
205
+ You may charge any price or no price for each copy that you convey,
206
+ and you may offer support or warranty protection for a fee.
207
+
208
+ 5. Conveying Modified Source Versions.
209
+
210
+ You may convey a work based on the Program, or the modifications to
211
+ produce it from the Program, in the form of source code under the
212
+ terms of section 4, provided that you also meet all of these conditions:
213
+
214
+ a) The work must carry prominent notices stating that you modified
215
+ it, and giving a relevant date.
216
+
217
+ b) The work must carry prominent notices stating that it is
218
+ released under this License and any conditions added under section
219
+ 7. This requirement modifies the requirement in section 4 to
220
+ "keep intact all notices".
221
+
222
+ c) You must license the entire work, as a whole, under this
223
+ License to anyone who comes into possession of a copy. This
224
+ License will therefore apply, along with any applicable section 7
225
+ additional terms, to the whole of the work, and all its parts,
226
+ regardless of how they are packaged. This License gives no
227
+ permission to license the work in any other way, but it does not
228
+ invalidate such permission if you have separately received it.
229
+
230
+ d) If the work has interactive user interfaces, each must display
231
+ Appropriate Legal Notices; however, if the Program has interactive
232
+ interfaces that do not display Appropriate Legal Notices, your
233
+ work need not make them do so.
234
+
235
+ A compilation of a covered work with other separate and independent
236
+ works, which are not by their nature extensions of the covered work,
237
+ and which are not combined with it such as to form a larger program,
238
+ in or on a volume of a storage or distribution medium, is called an
239
+ "aggregate" if the compilation and its resulting copyright are not
240
+ used to limit the access or legal rights of the compilation's users
241
+ beyond what the individual works permit. Inclusion of a covered work
242
+ in an aggregate does not cause this License to apply to the other
243
+ parts of the aggregate.
244
+
245
+ 6. Conveying Non-Source Forms.
246
+
247
+ You may convey a covered work in object code form under the terms
248
+ of sections 4 and 5, provided that you also convey the
249
+ machine-readable Corresponding Source under the terms of this License,
250
+ in one of these ways:
251
+
252
+ a) Convey the object code in, or embodied in, a physical product
253
+ (including a physical distribution medium), accompanied by the
254
+ Corresponding Source fixed on a durable physical medium
255
+ customarily used for software interchange.
256
+
257
+ b) Convey the object code in, or embodied in, a physical product
258
+ (including a physical distribution medium), accompanied by a
259
+ written offer, valid for at least three years and valid for as
260
+ long as you offer spare parts or customer support for that product
261
+ model, to give anyone who possesses the object code either (1) a
262
+ copy of the Corresponding Source for all the software in the
263
+ product that is covered by this License, on a durable physical
264
+ medium customarily used for software interchange, for a price no
265
+ more than your reasonable cost of physically performing this
266
+ conveying of source, or (2) access to copy the
267
+ Corresponding Source from a network server at no charge.
268
+
269
+ c) Convey individual copies of the object code with a copy of the
270
+ written offer to provide the Corresponding Source. This
271
+ alternative is allowed only occasionally and noncommercially, and
272
+ only if you received the object code with such an offer, in accord
273
+ with subsection 6b.
274
+
275
+ d) Convey the object code by offering access from a designated
276
+ place (gratis or for a charge), and offer equivalent access to the
277
+ Corresponding Source in the same way through the same place at no
278
+ further charge. You need not require recipients to copy the
279
+ Corresponding Source along with the object code. If the place to
280
+ copy the object code is a network server, the Corresponding Source
281
+ may be on a different server (operated by you or a third party)
282
+ that supports equivalent copying facilities, provided you maintain
283
+ clear directions next to the object code saying where to find the
284
+ Corresponding Source. Regardless of what server hosts the
285
+ Corresponding Source, you remain obligated to ensure that it is
286
+ available for as long as needed to satisfy these requirements.
287
+
288
+ e) Convey the object code using peer-to-peer transmission, provided
289
+ you inform other peers where the object code and Corresponding
290
+ Source of the work are being offered to the general public at no
291
+ charge under subsection 6d.
292
+
293
+ A separable portion of the object code, whose source code is excluded
294
+ from the Corresponding Source as a System Library, need not be
295
+ included in conveying the object code work.
296
+
297
+ A "User Product" is either (1) a "consumer product", which means any
298
+ tangible personal property which is normally used for personal, family,
299
+ or household purposes, or (2) anything designed or sold for incorporation
300
+ into a dwelling. In determining whether a product is a consumer product,
301
+ doubtful cases shall be resolved in favor of coverage. For a particular
302
+ product received by a particular user, "normally used" refers to a
303
+ typical or common use of that class of product, regardless of the status
304
+ of the particular user or of the way in which the particular user
305
+ actually uses, or expects or is expected to use, the product. A product
306
+ is a consumer product regardless of whether the product has substantial
307
+ commercial, industrial or non-consumer uses, unless such uses represent
308
+ the only significant mode of use of the product.
309
+
310
+ "Installation Information" for a User Product means any methods,
311
+ procedures, authorization keys, or other information required to install
312
+ and execute modified versions of a covered work in that User Product from
313
+ a modified version of its Corresponding Source. The information must
314
+ suffice to ensure that the continued functioning of the modified object
315
+ code is in no case prevented or interfered with solely because
316
+ modification has been made.
317
+
318
+ If you convey an object code work under this section in, or with, or
319
+ specifically for use in, a User Product, and the conveying occurs as
320
+ part of a transaction in which the right of possession and use of the
321
+ User Product is transferred to the recipient in perpetuity or for a
322
+ fixed term (regardless of how the transaction is characterized), the
323
+ Corresponding Source conveyed under this section must be accompanied
324
+ by the Installation Information. But this requirement does not apply
325
+ if neither you nor any third party retains the ability to install
326
+ modified object code on the User Product (for example, the work has
327
+ been installed in ROM).
328
+
329
+ The requirement to provide Installation Information does not include a
330
+ requirement to continue to provide support service, warranty, or updates
331
+ for a work that has been modified or installed by the recipient, or for
332
+ the User Product in which it has been modified or installed. Access to a
333
+ network may be denied when the modification itself materially and
334
+ adversely affects the operation of the network or violates the rules and
335
+ protocols for communication across the network.
336
+
337
+ Corresponding Source conveyed, and Installation Information provided,
338
+ in accord with this section must be in a format that is publicly
339
+ documented (and with an implementation available to the public in
340
+ source code form), and must require no special password or key for
341
+ unpacking, reading or copying.
342
+
343
+ 7. Additional Terms.
344
+
345
+ "Additional permissions" are terms that supplement the terms of this
346
+ License by making exceptions from one or more of its conditions.
347
+ Additional permissions that are applicable to the entire Program shall
348
+ be treated as though they were included in this License, to the extent
349
+ that they are valid under applicable law. If additional permissions
350
+ apply only to part of the Program, that part may be used separately
351
+ under those permissions, but the entire Program remains governed by
352
+ this License without regard to the additional permissions.
353
+
354
+ When you convey a copy of a covered work, you may at your option
355
+ remove any additional permissions from that copy, or from any part of
356
+ it. (Additional permissions may be written to require their own
357
+ removal in certain cases when you modify the work.) You may place
358
+ additional permissions on material, added by you to a covered work,
359
+ for which you have or can give appropriate copyright permission.
360
+
361
+ Notwithstanding any other provision of this License, for material you
362
+ add to a covered work, you may (if authorized by the copyright holders of
363
+ that material) supplement the terms of this License with terms:
364
+
365
+ a) Disclaiming warranty or limiting liability differently from the
366
+ terms of sections 15 and 16 of this License; or
367
+
368
+ b) Requiring preservation of specified reasonable legal notices or
369
+ author attributions in that material or in the Appropriate Legal
370
+ Notices displayed by works containing it; or
371
+
372
+ c) Prohibiting misrepresentation of the origin of that material, or
373
+ requiring that modified versions of such material be marked in
374
+ reasonable ways as different from the original version; or
375
+
376
+ d) Limiting the use for publicity purposes of names of licensors or
377
+ authors of the material; or
378
+
379
+ e) Declining to grant rights under trademark law for use of some
380
+ trade names, trademarks, or service marks; or
381
+
382
+ f) Requiring indemnification of licensors and authors of that
383
+ material by anyone who conveys the material (or modified versions of
384
+ it) with contractual assumptions of liability to the recipient, for
385
+ any liability that these contractual assumptions directly impose on
386
+ those licensors and authors.
387
+
388
+ All other non-permissive additional terms are considered "further
389
+ restrictions" within the meaning of section 10. If the Program as you
390
+ received it, or any part of it, contains a notice stating that it is
391
+ governed by this License along with a term that is a further
392
+ restriction, you may remove that term. If a license document contains
393
+ a further restriction but permits relicensing or conveying under this
394
+ License, you may add to a covered work material governed by the terms
395
+ of that license document, provided that the further restriction does
396
+ not survive such relicensing or conveying.
397
+
398
+ If you add terms to a covered work in accord with this section, you
399
+ must place, in the relevant source files, a statement of the
400
+ additional terms that apply to those files, or a notice indicating
401
+ where to find the applicable terms.
402
+
403
+ Additional terms, permissive or non-permissive, may be stated in the
404
+ form of a separately written license, or stated as exceptions;
405
+ the above requirements apply either way.
406
+
407
+ 8. Termination.
408
+
409
+ You may not propagate or modify a covered work except as expressly
410
+ provided under this License. Any attempt otherwise to propagate or
411
+ modify it is void, and will automatically terminate your rights under
412
+ this License (including any patent licenses granted under the third
413
+ paragraph of section 11).
414
+
415
+ However, if you cease all violation of this License, then your
416
+ license from a particular copyright holder is reinstated (a)
417
+ provisionally, unless and until the copyright holder explicitly and
418
+ finally terminates your license, and (b) permanently, if the copyright
419
+ holder fails to notify you of the violation by some reasonable means
420
+ prior to 60 days after the cessation.
421
+
422
+ Moreover, your license from a particular copyright holder is
423
+ reinstated permanently if the copyright holder notifies you of the
424
+ violation by some reasonable means, this is the first time you have
425
+ received notice of violation of this License (for any work) from that
426
+ copyright holder, and you cure the violation prior to 30 days after
427
+ your receipt of the notice.
428
+
429
+ Termination of your rights under this section does not terminate the
430
+ licenses of parties who have received copies or rights from you under
431
+ this License. If your rights have been terminated and not permanently
432
+ reinstated, you do not qualify to receive new licenses for the same
433
+ material under section 10.
434
+
435
+ 9. Acceptance Not Required for Having Copies.
436
+
437
+ You are not required to accept this License in order to receive or
438
+ run a copy of the Program. Ancillary propagation of a covered work
439
+ occurring solely as a consequence of using peer-to-peer transmission
440
+ to receive a copy likewise does not require acceptance. However,
441
+ nothing other than this License grants you permission to propagate or
442
+ modify any covered work. These actions infringe copyright if you do
443
+ not accept this License. Therefore, by modifying or propagating a
444
+ covered work, you indicate your acceptance of this License to do so.
445
+
446
+ 10. Automatic Licensing of Downstream Recipients.
447
+
448
+ Each time you convey a covered work, the recipient automatically
449
+ receives a license from the original licensors, to run, modify and
450
+ propagate that work, subject to this License. You are not responsible
451
+ for enforcing compliance by third parties with this License.
452
+
453
+ An "entity transaction" is a transaction transferring control of an
454
+ organization, or substantially all assets of one, or subdividing an
455
+ organization, or merging organizations. If propagation of a covered
456
+ work results from an entity transaction, each party to that
457
+ transaction who receives a copy of the work also receives whatever
458
+ licenses to the work the party's predecessor in interest had or could
459
+ give under the previous paragraph, plus a right to possession of the
460
+ Corresponding Source of the work from the predecessor in interest, if
461
+ the predecessor has it or can get it with reasonable efforts.
462
+
463
+ You may not impose any further restrictions on the exercise of the
464
+ rights granted or affirmed under this License. For example, you may
465
+ not impose a license fee, royalty, or other charge for exercise of
466
+ rights granted under this License, and you may not initiate litigation
467
+ (including a cross-claim or counterclaim in a lawsuit) alleging that
468
+ any patent claim is infringed by making, using, selling, offering for
469
+ sale, or importing the Program or any portion of it.
470
+
471
+ 11. Patents.
472
+
473
+ A "contributor" is a copyright holder who authorizes use under this
474
+ License of the Program or a work on which the Program is based. The
475
+ work thus licensed is called the contributor's "contributor version".
476
+
477
+ A contributor's "essential patent claims" are all patent claims
478
+ owned or controlled by the contributor, whether already acquired or
479
+ hereafter acquired, that would be infringed by some manner, permitted
480
+ by this License, of making, using, or selling its contributor version,
481
+ but do not include claims that would be infringed only as a
482
+ consequence of further modification of the contributor version. For
483
+ purposes of this definition, "control" includes the right to grant
484
+ patent sublicenses in a manner consistent with the requirements of
485
+ this License.
486
+
487
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
488
+ patent license under the contributor's essential patent claims, to
489
+ make, use, sell, offer for sale, import and otherwise run, modify and
490
+ propagate the contents of its contributor version.
491
+
492
+ In the following three paragraphs, a "patent license" is any express
493
+ agreement or commitment, however denominated, not to enforce a patent
494
+ (such as an express permission to practice a patent or covenant not to
495
+ sue for patent infringement). To "grant" such a patent license to a
496
+ party means to make such an agreement or commitment not to enforce a
497
+ patent against the party.
498
+
499
+ If you convey a covered work, knowingly relying on a patent license,
500
+ and the Corresponding Source of the work is not available for anyone
501
+ to copy, free of charge and under the terms of this License, through a
502
+ publicly available network server or other readily accessible means,
503
+ then you must either (1) cause the Corresponding Source to be so
504
+ available, or (2) arrange to deprive yourself of the benefit of the
505
+ patent license for this particular work, or (3) arrange, in a manner
506
+ consistent with the requirements of this License, to extend the patent
507
+ license to downstream recipients. "Knowingly relying" means you have
508
+ actual knowledge that, but for the patent license, your conveying the
509
+ covered work in a country, or your recipient's use of the covered work
510
+ in a country, would infringe one or more identifiable patents in that
511
+ country that you have reason to believe are valid.
512
+
513
+ If, pursuant to or in connection with a single transaction or
514
+ arrangement, you convey, or propagate by procuring conveyance of, a
515
+ covered work, and grant a patent license to some of the parties
516
+ receiving the covered work authorizing them to use, propagate, modify
517
+ or convey a specific copy of the covered work, then the patent license
518
+ you grant is automatically extended to all recipients of the covered
519
+ work and works based on it.
520
+
521
+ A patent license is "discriminatory" if it does not include within
522
+ the scope of its coverage, prohibits the exercise of, or is
523
+ conditioned on the non-exercise of one or more of the rights that are
524
+ specifically granted under this License. You may not convey a covered
525
+ work if you are a party to an arrangement with a third party that is
526
+ in the business of distributing software, under which you make payment
527
+ to the third party based on the extent of your activity of conveying
528
+ the work, and under which the third party grants, to any of the
529
+ parties who would receive the covered work from you, a discriminatory
530
+ patent license (a) in connection with copies of the covered work
531
+ conveyed by you (or copies made from those copies), or (b) primarily
532
+ for and in connection with specific products or compilations that
533
+ contain the covered work, unless you entered into that arrangement,
534
+ or that patent license was granted, prior to 28 March 2007.
535
+
536
+ Nothing in this License shall be construed as excluding or limiting
537
+ any implied license or other defenses to infringement that may
538
+ otherwise be available to you under applicable patent law.
539
+
540
+ 12. No Surrender of Others' Freedom.
541
+
542
+ If conditions are imposed on you (whether by court order, agreement or
543
+ otherwise) that contradict the conditions of this License, they do not
544
+ excuse you from the conditions of this License. If you cannot convey a
545
+ covered work so as to satisfy simultaneously your obligations under this
546
+ License and any other pertinent obligations, then as a consequence you may
547
+ not convey it at all. For example, if you agree to terms that obligate you
548
+ to collect a royalty for further conveying from those to whom you convey
549
+ the Program, the only way you could satisfy both those terms and this
550
+ License would be to refrain entirely from conveying the Program.
551
+
552
+ 13. Use with the GNU Affero General Public License.
553
+
554
+ Notwithstanding any other provision of this License, you have
555
+ permission to link or combine any covered work with a work licensed
556
+ under version 3 of the GNU Affero General Public License into a single
557
+ combined work, and to convey the resulting work. The terms of this
558
+ License will continue to apply to the part which is the covered work,
559
+ but the special requirements of the GNU Affero General Public License,
560
+ section 13, concerning interaction through a network will apply to the
561
+ combination as such.
562
+
563
+ 14. Revised Versions of this License.
564
+
565
+ The Free Software Foundation may publish revised and/or new versions of
566
+ the GNU General Public License from time to time. Such new versions will
567
+ be similar in spirit to the present version, but may differ in detail to
568
+ address new problems or concerns.
569
+
570
+ Each version is given a distinguishing version number. If the
571
+ Program specifies that a certain numbered version of the GNU General
572
+ Public License "or any later version" applies to it, you have the
573
+ option of following the terms and conditions either of that numbered
574
+ version or of any later version published by the Free Software
575
+ Foundation. If the Program does not specify a version number of the
576
+ GNU General Public License, you may choose any version ever published
577
+ by the Free Software Foundation.
578
+
579
+ If the Program specifies that a proxy can decide which future
580
+ versions of the GNU General Public License can be used, that proxy's
581
+ public statement of acceptance of a version permanently authorizes you
582
+ to choose that version for the Program.
583
+
584
+ Later license versions may give you additional or different
585
+ permissions. However, no additional obligations are imposed on any
586
+ author or copyright holder as a result of your choosing to follow a
587
+ later version.
588
+
589
+ 15. Disclaimer of Warranty.
590
+
591
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592
+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594
+ OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596
+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597
+ IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598
+ ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599
+
600
+ 16. Limitation of Liability.
601
+
602
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604
+ THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605
+ GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606
+ USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607
+ DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608
+ PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609
+ EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610
+ SUCH DAMAGES.
611
+
612
+ 17. Interpretation of Sections 15 and 16.
613
+
614
+ If the disclaimer of warranty and limitation of liability provided
615
+ above cannot be given local legal effect according to their terms,
616
+ reviewing courts shall apply local law that most closely approximates
617
+ an absolute waiver of all civil liability in connection with the
618
+ Program, unless a warranty or assumption of liability accompanies a
619
+ copy of the Program in return for a fee.
620
+
621
+ END OF TERMS AND CONDITIONS
622
+
623
+ How to Apply These Terms to Your New Programs
624
+
625
+ If you develop a new program, and you want it to be of the greatest
626
+ possible use to the public, the best way to achieve this is to make it
627
+ free software which everyone can redistribute and change under these terms.
628
+
629
+ To do so, attach the following notices to the program. It is safest
630
+ to attach them to the start of each source file to most effectively
631
+ state the exclusion of warranty; and each file should have at least
632
+ the "copyright" line and a pointer to where the full notice is found.
633
+
634
+ <one line to give the program's name and a brief idea of what it does.>
635
+ Copyright (C) <year> <name of author>
636
+
637
+ This program is free software: you can redistribute it and/or modify
638
+ it under the terms of the GNU General Public License as published by
639
+ the Free Software Foundation, either version 3 of the License, or
640
+ (at your option) any later version.
641
+
642
+ This program is distributed in the hope that it will be useful,
643
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
644
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645
+ GNU General Public License for more details.
646
+
647
+ You should have received a copy of the GNU General Public License
648
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
649
+
650
+ Also add information on how to contact you by electronic and paper mail.
651
+
652
+ If the program does terminal interaction, make it output a short
653
+ notice like this when it starts in an interactive mode:
654
+
655
+ <program> Copyright (C) <year> <name of author>
656
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657
+ This is free software, and you are welcome to redistribute it
658
+ under certain conditions; type `show c' for details.
659
+
660
+ The hypothetical commands `show w' and `show c' should show the appropriate
661
+ parts of the General Public License. Of course, your program's commands
662
+ might be different; for a GUI interface, you would use an "about box".
663
+
664
+ You should also get your employer (if you work as a programmer) or school,
665
+ if any, to sign a "copyright disclaimer" for the program, if necessary.
666
+ For more information on this, and how to apply and follow the GNU GPL, see
667
+ <https://www.gnu.org/licenses/>.
668
+
669
+ The GNU General Public License does not permit incorporating your program
670
+ into proprietary programs. If your program is a subroutine library, you
671
+ may consider it more useful to permit linking proprietary applications with
672
+ the library. If this is what you want to do, use the GNU Lesser General
673
+ Public License instead of this License. But first, please read
674
+ <https://www.gnu.org/licenses/why-not-lgpl.html>.
README.md CHANGED
@@ -7,7 +7,6 @@ sdk: gradio
7
  sdk_version: 3.32.0
8
  app_file: app.py
9
  pinned: false
10
- duplicated_from: qingxu98/gpt-academic
11
  ---
12
 
13
  # ChatGPT 学术优化
 
7
  sdk_version: 3.32.0
8
  app_file: app.py
9
  pinned: false
 
10
  ---
11
 
12
  # ChatGPT 学术优化
app.py CHANGED
@@ -17,8 +17,8 @@ def main():
17
 
18
  from check_proxy import get_current_version
19
  initial_prompt = "Serve me as a writing and programming assistant."
20
- title_html = f"<h1 align=\"center\">ChatGPT 学术优化</h1>"
21
- description = """感谢热情的[开发者们❤️]"""
22
 
23
  # 问询记录, python 版本建议3.9+(越新越好)
24
  import logging
@@ -56,7 +56,7 @@ def main():
56
  cancel_handles = []
57
  with gr.Blocks(title="ChatGPT 学术优化", theme=set_theme, analytics_enabled=False, css=advanced_css) as demo:
58
  gr.HTML(title_html)
59
- gr.HTML('''<center>BoFan AI提供技术支持,出此Claude 2.0 版本外,近期我将推出,基于我的微调模型的版本,模型现已经上线欢迎体验<a href="https://huggingface.co/fb700/chatglm-fitness-RLHF">下载地址</a></center>''')
60
  cookies = gr.State({'api_key': API_KEY, 'llm_model': LLM_MODEL})
61
  with gr_L1():
62
  with gr_L2(scale=2):
@@ -66,7 +66,7 @@ def main():
66
  with gr_L2(scale=1):
67
  with gr.Accordion("输入区", open=True) as area_input_primary:
68
  with gr.Row():
69
- txt = gr.Textbox(show_label=False, lines=2, placeholder="请直接输入问题").style(container=False)
70
  with gr.Row():
71
  submitBtn = gr.Button("提交", variant="primary")
72
  with gr.Row():
@@ -107,7 +107,7 @@ def main():
107
  system_prompt = gr.Textbox(show_label=True, placeholder=f"System Prompt", label="System prompt", value=initial_prompt)
108
  top_p = gr.Slider(minimum=-0, maximum=1.0, value=1.0, step=0.01,interactive=True, label="Top-p (nucleus sampling)",)
109
  temperature = gr.Slider(minimum=-0, maximum=2.0, value=1.0, step=0.01, interactive=True, label="Temperature",)
110
- max_length_sl = gr.Slider(minimum=256, maximum=4096, value=512, step=1, interactive=True, label="Local LLM MaxLength",)
111
  checkboxes = gr.CheckboxGroup(["基础功能区", "函数插件区", "底部输入区", "输入清除键", "插件参数区"], value=["基础功能区", "函数插件区"], label="显示/隐藏功能区")
112
  md_dropdown = gr.Dropdown(AVAIL_LLM_MODELS, value=LLM_MODEL, label="更换LLM模型/请求源").style(container=False)
113
 
@@ -200,7 +200,7 @@ def main():
200
  threading.Thread(target=warm_up_modules, name="warm-up", daemon=True).start()
201
 
202
  auto_opentab_delay()
203
- demo.queue(concurrency_count=CONCURRENT_COUNT).launch(server_name="0.0.0.0", share=False, favicon_path="docs/logo.png", auth=[["fbai", "Fbai!234"],["kmsmj", "017962"],["bofan", "bofan!234"],["dogfall", "@qq.com"]], blocked_paths=["config.py","config_private.py","docker-compose.yml","Dockerfile"])
204
 
205
  # 如果需要在二级路径下运行
206
  # CUSTOM_PATH, = get_conf('CUSTOM_PATH')
 
17
 
18
  from check_proxy import get_current_version
19
  initial_prompt = "Serve me as a writing and programming assistant."
20
+ title_html = f'<h1 align=\"center\">ChatGPT 学术优化 {get_current_version()}<a href="https://huggingface.co/fb700/chatglm-fitness-RLHF">(模型by帛凡Ai)</a></h1>'
21
+ description = """代码开源和更新[地址🚀](https://github.com/binary-husky/chatgpt_academic),感谢热情的[开发者们❤️](https://github.com/binary-husky/chatgpt_academic/graphs/contributors)"""
22
 
23
  # 问询记录, python 版本建议3.9+(越新越好)
24
  import logging
 
56
  cancel_handles = []
57
  with gr.Blocks(title="ChatGPT 学术优化", theme=set_theme, analytics_enabled=False, css=advanced_css) as demo:
58
  gr.HTML(title_html)
59
+ gr.HTML('''<center>本应用基于chatglm6b【帛凡 AI】的微调模型进行部署,模型中文总结能力优于GPT3.5,欢迎体验<a href="https://huggingface.co/fb700/chatglm-fitness-RLHF">下载地址</a></center>''')
60
  cookies = gr.State({'api_key': API_KEY, 'llm_model': LLM_MODEL})
61
  with gr_L1():
62
  with gr_L2(scale=2):
 
66
  with gr_L2(scale=1):
67
  with gr.Accordion("输入区", open=True) as area_input_primary:
68
  with gr.Row():
69
+ txt = gr.Textbox(show_label=False, lines=2, placeholder="输入问题或API密钥,输入多个密钥时,用英文逗号间隔。支持OpenAI密钥和API2D密钥共存。").style(container=False)
70
  with gr.Row():
71
  submitBtn = gr.Button("提交", variant="primary")
72
  with gr.Row():
 
107
  system_prompt = gr.Textbox(show_label=True, placeholder=f"System Prompt", label="System prompt", value=initial_prompt)
108
  top_p = gr.Slider(minimum=-0, maximum=1.0, value=1.0, step=0.01,interactive=True, label="Top-p (nucleus sampling)",)
109
  temperature = gr.Slider(minimum=-0, maximum=2.0, value=1.0, step=0.01, interactive=True, label="Temperature",)
110
+ max_length_sl = gr.Slider(minimum=256, maximum=40960, value=5120, step=1, interactive=True, label="Local LLM MaxLength",)
111
  checkboxes = gr.CheckboxGroup(["基础功能区", "函数插件区", "底部输入区", "输入清除键", "插件参数区"], value=["基础功能区", "函数插件区"], label="显示/隐藏功能区")
112
  md_dropdown = gr.Dropdown(AVAIL_LLM_MODELS, value=LLM_MODEL, label="更换LLM模型/请求源").style(container=False)
113
 
 
200
  threading.Thread(target=warm_up_modules, name="warm-up", daemon=True).start()
201
 
202
  auto_opentab_delay()
203
+ demo.queue(concurrency_count=CONCURRENT_COUNT).launch(server_name="0.0.0.0", share=False, favicon_path="docs/logo.png", blocked_paths=["config.py","config_private.py","docker-compose.yml","Dockerfile"])
204
 
205
  # 如果需要在二级路径下运行
206
  # CUSTOM_PATH, = get_conf('CUSTOM_PATH')
check_proxy.py CHANGED
@@ -150,6 +150,12 @@ def warm_up_modules():
150
  enc.encode("模块预热", disallowed_special=())
151
  enc = model_info["gpt-4"]['tokenizer']
152
  enc.encode("模块预热", disallowed_special=())
 
 
 
 
 
 
153
 
154
  if __name__ == '__main__':
155
  import os
 
150
  enc.encode("模块预热", disallowed_special=())
151
  enc = model_info["gpt-4"]['tokenizer']
152
  enc.encode("模块预热", disallowed_special=())
153
+ from request_llm.bridge_chatglm import predict_no_ui_long_connection
154
+ llm_kwargs = {'max_length': 51200,'top_p': 1,'temperature': 1,}
155
+ result = predict_no_ui_long_connection( inputs="请问什么是质子?",
156
+ llm_kwargs=llm_kwargs,
157
+ history=["你好", "我好!"],
158
+ sys_prompt="")
159
 
160
  if __name__ == '__main__':
161
  import os
config.py CHANGED
@@ -1,5 +1,5 @@
1
  # [step 1]>> 例如: API_KEY = "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" (此key无效)
2
- API_KEY = "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" # 可同时填写多个API-KEY,用英文逗号分割,例如API_KEY = "sk-openaikey1,sk-openaikey2,fkxxxx-api2dkey1,fkxxxx-api2dkey2"
3
 
4
 
5
  # [step 2]>> 改为True应用代理,如果直接在海外服务器部署,此处不修改
@@ -46,11 +46,11 @@ WEB_PORT = -1
46
  MAX_RETRY = 2
47
 
48
  # OpenAI模型选择是(gpt4现在只对申请成功的人开放)
49
- LLM_MODEL = "gpt-3.5-turbo" # 可选 "chatglm"
50
  AVAIL_LLM_MODELS = ["newbing-free", "gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "api2d-gpt-3.5-turbo"]
51
 
52
  # 本地LLM模型如ChatGLM的执行方式 CPU/GPU
53
- LOCAL_MODEL_DEVICE = "cpu" # 可选 "cuda"
54
 
55
  # 设置gradio的并行线程数(不需要修改)
56
  CONCURRENT_COUNT = 100
@@ -60,18 +60,13 @@ ADD_WAIFU = False
60
 
61
  # 设置用户名和密码(不需要修改)(相关功能不稳定,与gradio版本和网络都相关,如果本地使用不建议加这个)
62
  # [("username", "password"), ("username2", "password2"), ...]
63
- [("fbai", "Fbai!234"), ("username2", "password2"), ("bofan", "bofan!234"), ...]
64
  AUTHENTICATION = []
65
 
66
-
67
  # 重新URL重新定向,实现更换API_URL的作用(常规情况下,不要修改!!)
68
  # (高危设置!通过修改此设置,您将把您的API-KEY和对话隐私完全暴露给您设定的中间人!)
69
  # 格式 {"https://api.openai.com/v1/chat/completions": "在这里填写重定向的api.openai.com的URL"}
70
  # 例如 API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "https://ai.open.com/api/conversation"}
71
- #url1="http://138.3.215.133:8787/v1/chat/completions"
72
-
73
- API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "http://138.3.215.133:8787/v1/chat/completions"}
74
-
75
 
76
  # 如果需要在二级路径下运行(常规情况下,不要修改!!)(需要配合修改main.py才能生效!)
77
  CUSTOM_PATH = "/"
 
1
  # [step 1]>> 例如: API_KEY = "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" (此key无效)
2
+ API_KEY = "sk-此处填API密钥" # 可同时填写多个API-KEY,用英文逗号分割,例如API_KEY = "sk-openaikey1,sk-openaikey2,fkxxxx-api2dkey1,fkxxxx-api2dkey2"
3
 
4
 
5
  # [step 2]>> 改为True应用代理,如果直接在海外服务器部署,此处不修改
 
46
  MAX_RETRY = 2
47
 
48
  # OpenAI模型选择是(gpt4现在只对申请成功的人开放)
49
+ LLM_MODEL = "chatglm" # 可选 "chatglm"
50
  AVAIL_LLM_MODELS = ["newbing-free", "gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "api2d-gpt-3.5-turbo"]
51
 
52
  # 本地LLM模型如ChatGLM的执行方式 CPU/GPU
53
+ LOCAL_MODEL_DEVICE = "cuda" # 可选 "cuda"
54
 
55
  # 设置gradio的并行线程数(不需要修改)
56
  CONCURRENT_COUNT = 100
 
60
 
61
  # 设置用户名和密码(不需要修改)(相关功能不稳定,与gradio版本和网络都相关,如果本地使用不建议加这个)
62
  # [("username", "password"), ("username2", "password2"), ...]
 
63
  AUTHENTICATION = []
64
 
 
65
  # 重新URL重新定向,实现更换API_URL的作用(常规情况下,不要修改!!)
66
  # (高危设置!通过修改此设置,您将把您的API-KEY和对话隐私完全暴露给您设定的中间人!)
67
  # 格式 {"https://api.openai.com/v1/chat/completions": "在这里填写重定向的api.openai.com的URL"}
68
  # 例如 API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "https://ai.open.com/api/conversation"}
69
+ API_URL_REDIRECT = {}
 
 
 
70
 
71
  # 如果需要在二级路径下运行(常规情况下,不要修改!!)(需要配合修改main.py才能生效!)
72
  CUSTOM_PATH = "/"
crazy_functions/test_project/cpp/cppipc/buffer.cpp CHANGED
@@ -1,87 +1,87 @@
1
- #include "libipc/buffer.h"
2
- #include "libipc/utility/pimpl.h"
3
-
4
- #include <cstring>
5
-
6
- namespace ipc {
7
-
8
- bool operator==(buffer const & b1, buffer const & b2) {
9
- return (b1.size() == b2.size()) && (std::memcmp(b1.data(), b2.data(), b1.size()) == 0);
10
- }
11
-
12
- bool operator!=(buffer const & b1, buffer const & b2) {
13
- return !(b1 == b2);
14
- }
15
-
16
- class buffer::buffer_ : public pimpl<buffer_> {
17
- public:
18
- void* p_;
19
- std::size_t s_;
20
- void* a_;
21
- buffer::destructor_t d_;
22
-
23
- buffer_(void* p, std::size_t s, buffer::destructor_t d, void* a)
24
- : p_(p), s_(s), a_(a), d_(d) {
25
- }
26
-
27
- ~buffer_() {
28
- if (d_ == nullptr) return;
29
- d_((a_ == nullptr) ? p_ : a_, s_);
30
- }
31
- };
32
-
33
- buffer::buffer()
34
- : buffer(nullptr, 0, nullptr, nullptr) {
35
- }
36
-
37
- buffer::buffer(void* p, std::size_t s, destructor_t d)
38
- : p_(p_->make(p, s, d, nullptr)) {
39
- }
40
-
41
- buffer::buffer(void* p, std::size_t s, destructor_t d, void* additional)
42
- : p_(p_->make(p, s, d, additional)) {
43
- }
44
-
45
- buffer::buffer(void* p, std::size_t s)
46
- : buffer(p, s, nullptr) {
47
- }
48
-
49
- buffer::buffer(char const & c)
50
- : buffer(const_cast<char*>(&c), 1) {
51
- }
52
-
53
- buffer::buffer(buffer&& rhs)
54
- : buffer() {
55
- swap(rhs);
56
- }
57
-
58
- buffer::~buffer() {
59
- p_->clear();
60
- }
61
-
62
- void buffer::swap(buffer& rhs) {
63
- std::swap(p_, rhs.p_);
64
- }
65
-
66
- buffer& buffer::operator=(buffer rhs) {
67
- swap(rhs);
68
- return *this;
69
- }
70
-
71
- bool buffer::empty() const noexcept {
72
- return (impl(p_)->p_ == nullptr) || (impl(p_)->s_ == 0);
73
- }
74
-
75
- void* buffer::data() noexcept {
76
- return impl(p_)->p_;
77
- }
78
-
79
- void const * buffer::data() const noexcept {
80
- return impl(p_)->p_;
81
- }
82
-
83
- std::size_t buffer::size() const noexcept {
84
- return impl(p_)->s_;
85
- }
86
-
87
- } // namespace ipc
 
1
+ #include "libipc/buffer.h"
2
+ #include "libipc/utility/pimpl.h"
3
+
4
+ #include <cstring>
5
+
6
+ namespace ipc {
7
+
8
+ bool operator==(buffer const & b1, buffer const & b2) {
9
+ return (b1.size() == b2.size()) && (std::memcmp(b1.data(), b2.data(), b1.size()) == 0);
10
+ }
11
+
12
+ bool operator!=(buffer const & b1, buffer const & b2) {
13
+ return !(b1 == b2);
14
+ }
15
+
16
+ class buffer::buffer_ : public pimpl<buffer_> {
17
+ public:
18
+ void* p_;
19
+ std::size_t s_;
20
+ void* a_;
21
+ buffer::destructor_t d_;
22
+
23
+ buffer_(void* p, std::size_t s, buffer::destructor_t d, void* a)
24
+ : p_(p), s_(s), a_(a), d_(d) {
25
+ }
26
+
27
+ ~buffer_() {
28
+ if (d_ == nullptr) return;
29
+ d_((a_ == nullptr) ? p_ : a_, s_);
30
+ }
31
+ };
32
+
33
+ buffer::buffer()
34
+ : buffer(nullptr, 0, nullptr, nullptr) {
35
+ }
36
+
37
+ buffer::buffer(void* p, std::size_t s, destructor_t d)
38
+ : p_(p_->make(p, s, d, nullptr)) {
39
+ }
40
+
41
+ buffer::buffer(void* p, std::size_t s, destructor_t d, void* additional)
42
+ : p_(p_->make(p, s, d, additional)) {
43
+ }
44
+
45
+ buffer::buffer(void* p, std::size_t s)
46
+ : buffer(p, s, nullptr) {
47
+ }
48
+
49
+ buffer::buffer(char const & c)
50
+ : buffer(const_cast<char*>(&c), 1) {
51
+ }
52
+
53
+ buffer::buffer(buffer&& rhs)
54
+ : buffer() {
55
+ swap(rhs);
56
+ }
57
+
58
+ buffer::~buffer() {
59
+ p_->clear();
60
+ }
61
+
62
+ void buffer::swap(buffer& rhs) {
63
+ std::swap(p_, rhs.p_);
64
+ }
65
+
66
+ buffer& buffer::operator=(buffer rhs) {
67
+ swap(rhs);
68
+ return *this;
69
+ }
70
+
71
+ bool buffer::empty() const noexcept {
72
+ return (impl(p_)->p_ == nullptr) || (impl(p_)->s_ == 0);
73
+ }
74
+
75
+ void* buffer::data() noexcept {
76
+ return impl(p_)->p_;
77
+ }
78
+
79
+ void const * buffer::data() const noexcept {
80
+ return impl(p_)->p_;
81
+ }
82
+
83
+ std::size_t buffer::size() const noexcept {
84
+ return impl(p_)->s_;
85
+ }
86
+
87
+ } // namespace ipc
crazy_functions/test_project/cpp/cppipc/ipc.cpp CHANGED
@@ -1,701 +1,701 @@
1
-
2
- #include <type_traits>
3
- #include <cstring>
4
- #include <algorithm>
5
- #include <utility> // std::pair, std::move, std::forward
6
- #include <atomic>
7
- #include <type_traits> // aligned_storage_t
8
- #include <string>
9
- #include <vector>
10
- #include <array>
11
- #include <cassert>
12
-
13
- #include "libipc/ipc.h"
14
- #include "libipc/def.h"
15
- #include "libipc/shm.h"
16
- #include "libipc/pool_alloc.h"
17
- #include "libipc/queue.h"
18
- #include "libipc/policy.h"
19
- #include "libipc/rw_lock.h"
20
- #include "libipc/waiter.h"
21
-
22
- #include "libipc/utility/log.h"
23
- #include "libipc/utility/id_pool.h"
24
- #include "libipc/utility/scope_guard.h"
25
- #include "libipc/utility/utility.h"
26
-
27
- #include "libipc/memory/resource.h"
28
- #include "libipc/platform/detail.h"
29
- #include "libipc/circ/elem_array.h"
30
-
31
- namespace {
32
-
33
- using msg_id_t = std::uint32_t;
34
- using acc_t = std::atomic<msg_id_t>;
35
-
36
- template <std::size_t DataSize, std::size_t AlignSize>
37
- struct msg_t;
38
-
39
- template <std::size_t AlignSize>
40
- struct msg_t<0, AlignSize> {
41
- msg_id_t cc_id_;
42
- msg_id_t id_;
43
- std::int32_t remain_;
44
- bool storage_;
45
- };
46
-
47
- template <std::size_t DataSize, std::size_t AlignSize>
48
- struct msg_t : msg_t<0, AlignSize> {
49
- std::aligned_storage_t<DataSize, AlignSize> data_ {};
50
-
51
- msg_t() = default;
52
- msg_t(msg_id_t cc_id, msg_id_t id, std::int32_t remain, void const * data, std::size_t size)
53
- : msg_t<0, AlignSize> {cc_id, id, remain, (data == nullptr) || (size == 0)} {
54
- if (this->storage_) {
55
- if (data != nullptr) {
56
- // copy storage-id
57
- *reinterpret_cast<ipc::storage_id_t*>(&data_) =
58
- *static_cast<ipc::storage_id_t const *>(data);
59
- }
60
- }
61
- else std::memcpy(&data_, data, size);
62
- }
63
- };
64
-
65
- template <typename T>
66
- ipc::buff_t make_cache(T& data, std::size_t size) {
67
- auto ptr = ipc::mem::alloc(size);
68
- std::memcpy(ptr, &data, (ipc::detail::min)(sizeof(data), size));
69
- return { ptr, size, ipc::mem::free };
70
- }
71
-
72
- struct cache_t {
73
- std::size_t fill_;
74
- ipc::buff_t buff_;
75
-
76
- cache_t(std::size_t f, ipc::buff_t && b)
77
- : fill_(f), buff_(std::move(b))
78
- {}
79
-
80
- void append(void const * data, std::size_t size) {
81
- if (fill_ >= buff_.size() || data == nullptr || size == 0) return;
82
- auto new_fill = (ipc::detail::min)(fill_ + size, buff_.size());
83
- std::memcpy(static_cast<ipc::byte_t*>(buff_.data()) + fill_, data, new_fill - fill_);
84
- fill_ = new_fill;
85
- }
86
- };
87
-
88
- auto cc_acc() {
89
- static ipc::shm::handle acc_h("__CA_CONN__", sizeof(acc_t));
90
- return static_cast<acc_t*>(acc_h.get());
91
- }
92
-
93
- IPC_CONSTEXPR_ std::size_t align_chunk_size(std::size_t size) noexcept {
94
- return (((size - 1) / ipc::large_msg_align) + 1) * ipc::large_msg_align;
95
- }
96
-
97
- IPC_CONSTEXPR_ std::size_t calc_chunk_size(std::size_t size) noexcept {
98
- return ipc::make_align(alignof(std::max_align_t), align_chunk_size(
99
- ipc::make_align(alignof(std::max_align_t), sizeof(std::atomic<ipc::circ::cc_t>)) + size));
100
- }
101
-
102
- struct chunk_t {
103
- std::atomic<ipc::circ::cc_t> &conns() noexcept {
104
- return *reinterpret_cast<std::atomic<ipc::circ::cc_t> *>(this);
105
- }
106
-
107
- void *data() noexcept {
108
- return reinterpret_cast<ipc::byte_t *>(this)
109
- + ipc::make_align(alignof(std::max_align_t), sizeof(std::atomic<ipc::circ::cc_t>));
110
- }
111
- };
112
-
113
- struct chunk_info_t {
114
- ipc::id_pool<> pool_;
115
- ipc::spin_lock lock_;
116
-
117
- IPC_CONSTEXPR_ static std::size_t chunks_mem_size(std::size_t chunk_size) noexcept {
118
- return ipc::id_pool<>::max_count * chunk_size;
119
- }
120
-
121
- ipc::byte_t *chunks_mem() noexcept {
122
- return reinterpret_cast<ipc::byte_t *>(this + 1);
123
- }
124
-
125
- chunk_t *at(std::size_t chunk_size, ipc::storage_id_t id) noexcept {
126
- if (id < 0) return nullptr;
127
- return reinterpret_cast<chunk_t *>(chunks_mem() + (chunk_size * id));
128
- }
129
- };
130
-
131
- auto& chunk_storages() {
132
- class chunk_handle_t {
133
- ipc::shm::handle handle_;
134
-
135
- public:
136
- chunk_info_t *get_info(std::size_t chunk_size) {
137
- if (!handle_.valid() &&
138
- !handle_.acquire( ("__CHUNK_INFO__" + ipc::to_string(chunk_size)).c_str(),
139
- sizeof(chunk_info_t) + chunk_info_t::chunks_mem_size(chunk_size) )) {
140
- ipc::error("[chunk_storages] chunk_shm.id_info_.acquire failed: chunk_size = %zd\n", chunk_size);
141
- return nullptr;
142
- }
143
- auto info = static_cast<chunk_info_t*>(handle_.get());
144
- if (info == nullptr) {
145
- ipc::error("[chunk_storages] chunk_shm.id_info_.get failed: chunk_size = %zd\n", chunk_size);
146
- return nullptr;
147
- }
148
- return info;
149
- }
150
- };
151
- static ipc::map<std::size_t, chunk_handle_t> chunk_hs;
152
- return chunk_hs;
153
- }
154
-
155
- chunk_info_t *chunk_storage_info(std::size_t chunk_size) {
156
- auto &storages = chunk_storages();
157
- std::decay_t<decltype(storages)>::iterator it;
158
- {
159
- static ipc::rw_lock lock;
160
- IPC_UNUSED_ std::shared_lock<ipc::rw_lock> guard {lock};
161
- if ((it = storages.find(chunk_size)) == storages.end()) {
162
- using chunk_handle_t = std::decay_t<decltype(storages)>::value_type::second_type;
163
- guard.unlock();
164
- IPC_UNUSED_ std::lock_guard<ipc::rw_lock> guard {lock};
165
- it = storages.emplace(chunk_size, chunk_handle_t{}).first;
166
- }
167
- }
168
- return it->second.get_info(chunk_size);
169
- }
170
-
171
- std::pair<ipc::storage_id_t, void*> acquire_storage(std::size_t size, ipc::circ::cc_t conns) {
172
- std::size_t chunk_size = calc_chunk_size(size);
173
- auto info = chunk_storage_info(chunk_size);
174
- if (info == nullptr) return {};
175
-
176
- info->lock_.lock();
177
- info->pool_.prepare();
178
- // got an unique id
179
- auto id = info->pool_.acquire();
180
- info->lock_.unlock();
181
-
182
- auto chunk = info->at(chunk_size, id);
183
- if (chunk == nullptr) return {};
184
- chunk->conns().store(conns, std::memory_order_relaxed);
185
- return { id, chunk->data() };
186
- }
187
-
188
- void *find_storage(ipc::storage_id_t id, std::size_t size) {
189
- if (id < 0) {
190
- ipc::error("[find_storage] id is invalid: id = %ld, size = %zd\n", (long)id, size);
191
- return nullptr;
192
- }
193
- std::size_t chunk_size = calc_chunk_size(size);
194
- auto info = chunk_storage_info(chunk_size);
195
- if (info == nullptr) return nullptr;
196
- return info->at(chunk_size, id)->data();
197
- }
198
-
199
- void release_storage(ipc::storage_id_t id, std::size_t size) {
200
- if (id < 0) {
201
- ipc::error("[release_storage] id is invalid: id = %ld, size = %zd\n", (long)id, size);
202
- return;
203
- }
204
- std::size_t chunk_size = calc_chunk_size(size);
205
- auto info = chunk_storage_info(chunk_size);
206
- if (info == nullptr) return;
207
- info->lock_.lock();
208
- info->pool_.release(id);
209
- info->lock_.unlock();
210
- }
211
-
212
- template <ipc::relat Rp, ipc::relat Rc>
213
- bool sub_rc(ipc::wr<Rp, Rc, ipc::trans::unicast>,
214
- std::atomic<ipc::circ::cc_t> &/*conns*/, ipc::circ::cc_t /*curr_conns*/, ipc::circ::cc_t /*conn_id*/) noexcept {
215
- return true;
216
- }
217
-
218
- template <ipc::relat Rp, ipc::relat Rc>
219
- bool sub_rc(ipc::wr<Rp, Rc, ipc::trans::broadcast>,
220
- std::atomic<ipc::circ::cc_t> &conns, ipc::circ::cc_t curr_conns, ipc::circ::cc_t conn_id) noexcept {
221
- auto last_conns = curr_conns & ~conn_id;
222
- for (unsigned k = 0;;) {
223
- auto chunk_conns = conns.load(std::memory_order_acquire);
224
- if (conns.compare_exchange_weak(chunk_conns, chunk_conns & last_conns, std::memory_order_release)) {
225
- return (chunk_conns & last_conns) == 0;
226
- }
227
- ipc::yield(k);
228
- }
229
- }
230
-
231
- template <typename Flag>
232
- void recycle_storage(ipc::storage_id_t id, std::size_t size, ipc::circ::cc_t curr_conns, ipc::circ::cc_t conn_id) {
233
- if (id < 0) {
234
- ipc::error("[recycle_storage] id is invalid: id = %ld, size = %zd\n", (long)id, size);
235
- return;
236
- }
237
- std::size_t chunk_size = calc_chunk_size(size);
238
- auto info = chunk_storage_info(chunk_size);
239
- if (info == nullptr) return;
240
-
241
- auto chunk = info->at(chunk_size, id);
242
- if (chunk == nullptr) return;
243
-
244
- if (!sub_rc(Flag{}, chunk->conns(), curr_conns, conn_id)) {
245
- return;
246
- }
247
- info->lock_.lock();
248
- info->pool_.release(id);
249
- info->lock_.unlock();
250
- }
251
-
252
- template <typename MsgT>
253
- bool clear_message(void* p) {
254
- auto msg = static_cast<MsgT*>(p);
255
- if (msg->storage_) {
256
- std::int32_t r_size = static_cast<std::int32_t>(ipc::data_length) + msg->remain_;
257
- if (r_size <= 0) {
258
- ipc::error("[clear_message] invalid msg size: %d\n", (int)r_size);
259
- return true;
260
- }
261
- release_storage(
262
- *reinterpret_cast<ipc::storage_id_t*>(&msg->data_),
263
- static_cast<std::size_t>(r_size));
264
- }
265
- return true;
266
- }
267
-
268
- struct conn_info_head {
269
-
270
- ipc::string name_;
271
- msg_id_t cc_id_; // connection-info id
272
- ipc::detail::waiter cc_waiter_, wt_waiter_, rd_waiter_;
273
- ipc::shm::handle acc_h_;
274
-
275
- conn_info_head(char const * name)
276
- : name_ {name}
277
- , cc_id_ {(cc_acc() == nullptr) ? 0 : cc_acc()->fetch_add(1, std::memory_order_relaxed)}
278
- , cc_waiter_{("__CC_CONN__" + name_).c_str()}
279
- , wt_waiter_{("__WT_CONN__" + name_).c_str()}
280
- , rd_waiter_{("__RD_CONN__" + name_).c_str()}
281
- , acc_h_ {("__AC_CONN__" + name_).c_str(), sizeof(acc_t)} {
282
- }
283
-
284
- void quit_waiting() {
285
- cc_waiter_.quit_waiting();
286
- wt_waiter_.quit_waiting();
287
- rd_waiter_.quit_waiting();
288
- }
289
-
290
- auto acc() {
291
- return static_cast<acc_t*>(acc_h_.get());
292
- }
293
-
294
- auto& recv_cache() {
295
- thread_local ipc::unordered_map<msg_id_t, cache_t> tls;
296
- return tls;
297
- }
298
- };
299
-
300
- template <typename W, typename F>
301
- bool wait_for(W& waiter, F&& pred, std::uint64_t tm) {
302
- if (tm == 0) return !pred();
303
- for (unsigned k = 0; pred();) {
304
- bool ret = true;
305
- ipc::sleep(k, [&k, &ret, &waiter, &pred, tm] {
306
- ret = waiter.wait_if(std::forward<F>(pred), tm);
307
- k = 0;
308
- });
309
- if (!ret) return false; // timeout or fail
310
- if (k == 0) break; // k has been reset
311
- }
312
- return true;
313
- }
314
-
315
- template <typename Policy,
316
- std::size_t DataSize = ipc::data_length,
317
- std::size_t AlignSize = (ipc::detail::min)(DataSize, alignof(std::max_align_t))>
318
- struct queue_generator {
319
-
320
- using queue_t = ipc::queue<msg_t<DataSize, AlignSize>, Policy>;
321
-
322
- struct conn_info_t : conn_info_head {
323
- queue_t que_;
324
-
325
- conn_info_t(char const * name)
326
- : conn_info_head{name}
327
- , que_{("__QU_CONN__" +
328
- ipc::to_string(DataSize) + "__" +
329
- ipc::to_string(AlignSize) + "__" + name).c_str()} {
330
- }
331
-
332
- void disconnect_receiver() {
333
- bool dis = que_.disconnect();
334
- this->quit_waiting();
335
- if (dis) {
336
- this->recv_cache().clear();
337
- }
338
- }
339
- };
340
- };
341
-
342
- template <typename Policy>
343
- struct detail_impl {
344
-
345
- using policy_t = Policy;
346
- using flag_t = typename policy_t::flag_t;
347
- using queue_t = typename queue_generator<policy_t>::queue_t;
348
- using conn_info_t = typename queue_generator<policy_t>::conn_info_t;
349
-
350
- constexpr static conn_info_t* info_of(ipc::handle_t h) noexcept {
351
- return static_cast<conn_info_t*>(h);
352
- }
353
-
354
- constexpr static queue_t* queue_of(ipc::handle_t h) noexcept {
355
- return (info_of(h) == nullptr) ? nullptr : &(info_of(h)->que_);
356
- }
357
-
358
- /* API implementations */
359
-
360
- static void disconnect(ipc::handle_t h) {
361
- auto que = queue_of(h);
362
- if (que == nullptr) {
363
- return;
364
- }
365
- que->shut_sending();
366
- assert(info_of(h) != nullptr);
367
- info_of(h)->disconnect_receiver();
368
- }
369
-
370
- static bool reconnect(ipc::handle_t * ph, bool start_to_recv) {
371
- assert(ph != nullptr);
372
- assert(*ph != nullptr);
373
- auto que = queue_of(*ph);
374
- if (que == nullptr) {
375
- return false;
376
- }
377
- if (start_to_recv) {
378
- que->shut_sending();
379
- if (que->connect()) { // wouldn't connect twice
380
- info_of(*ph)->cc_waiter_.broadcast();
381
- return true;
382
- }
383
- return false;
384
- }
385
- // start_to_recv == false
386
- if (que->connected()) {
387
- info_of(*ph)->disconnect_receiver();
388
- }
389
- return que->ready_sending();
390
- }
391
-
392
- static bool connect(ipc::handle_t * ph, char const * name, bool start_to_recv) {
393
- assert(ph != nullptr);
394
- if (*ph == nullptr) {
395
- *ph = ipc::mem::alloc<conn_info_t>(name);
396
- }
397
- return reconnect(ph, start_to_recv);
398
- }
399
-
400
- static void destroy(ipc::handle_t h) {
401
- disconnect(h);
402
- ipc::mem::free(info_of(h));
403
- }
404
-
405
- static std::size_t recv_count(ipc::handle_t h) noexcept {
406
- auto que = queue_of(h);
407
- if (que == nullptr) {
408
- return ipc::invalid_value;
409
- }
410
- return que->conn_count();
411
- }
412
-
413
- static bool wait_for_recv(ipc::handle_t h, std::size_t r_count, std::uint64_t tm) {
414
- auto que = queue_of(h);
415
- if (que == nullptr) {
416
- return false;
417
- }
418
- return wait_for(info_of(h)->cc_waiter_, [que, r_count] {
419
- return que->conn_count() < r_count;
420
- }, tm);
421
- }
422
-
423
- template <typename F>
424
- static bool send(F&& gen_push, ipc::handle_t h, void const * data, std::size_t size) {
425
- if (data == nullptr || size == 0) {
426
- ipc::error("fail: send(%p, %zd)\n", data, size);
427
- return false;
428
- }
429
- auto que = queue_of(h);
430
- if (que == nullptr) {
431
- ipc::error("fail: send, queue_of(h) == nullptr\n");
432
- return false;
433
- }
434
- if (que->elems() == nullptr) {
435
- ipc::error("fail: send, queue_of(h)->elems() == nullptr\n");
436
- return false;
437
- }
438
- if (!que->ready_sending()) {
439
- ipc::error("fail: send, que->ready_sending() == false\n");
440
- return false;
441
- }
442
- ipc::circ::cc_t conns = que->elems()->connections(std::memory_order_relaxed);
443
- if (conns == 0) {
444
- ipc::error("fail: send, there is no receiver on this connection.\n");
445
- return false;
446
- }
447
- // calc a new message id
448
- auto acc = info_of(h)->acc();
449
- if (acc == nullptr) {
450
- ipc::error("fail: send, info_of(h)->acc() == nullptr\n");
451
- return false;
452
- }
453
- auto msg_id = acc->fetch_add(1, std::memory_order_relaxed);
454
- auto try_push = std::forward<F>(gen_push)(info_of(h), que, msg_id);
455
- if (size > ipc::large_msg_limit) {
456
- auto dat = acquire_storage(size, conns);
457
- void * buf = dat.second;
458
- if (buf != nullptr) {
459
- std::memcpy(buf, data, size);
460
- return try_push(static_cast<std::int32_t>(size) -
461
- static_cast<std::int32_t>(ipc::data_length), &(dat.first), 0);
462
- }
463
- // try using message fragment
464
- //ipc::log("fail: shm::handle for big message. msg_id: %zd, size: %zd\n", msg_id, size);
465
- }
466
- // push message fragment
467
- std::int32_t offset = 0;
468
- for (std::int32_t i = 0; i < static_cast<std::int32_t>(size / ipc::data_length); ++i, offset += ipc::data_length) {
469
- if (!try_push(static_cast<std::int32_t>(size) - offset - static_cast<std::int32_t>(ipc::data_length),
470
- static_cast<ipc::byte_t const *>(data) + offset, ipc::data_length)) {
471
- return false;
472
- }
473
- }
474
- // if remain > 0, this is the last message fragment
475
- std::int32_t remain = static_cast<std::int32_t>(size) - offset;
476
- if (remain > 0) {
477
- if (!try_push(remain - static_cast<std::int32_t>(ipc::data_length),
478
- static_cast<ipc::byte_t const *>(data) + offset,
479
- static_cast<std::size_t>(remain))) {
480
- return false;
481
- }
482
- }
483
- return true;
484
- }
485
-
486
- static bool send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
487
- return send([tm](auto info, auto que, auto msg_id) {
488
- return [tm, info, que, msg_id](std::int32_t remain, void const * data, std::size_t size) {
489
- if (!wait_for(info->wt_waiter_, [&] {
490
- return !que->push(
491
- [](void*) { return true; },
492
- info->cc_id_, msg_id, remain, data, size);
493
- }, tm)) {
494
- ipc::log("force_push: msg_id = %zd, remain = %d, size = %zd\n", msg_id, remain, size);
495
- if (!que->force_push(
496
- clear_message<typename queue_t::value_t>,
497
- info->cc_id_, msg_id, remain, data, size)) {
498
- return false;
499
- }
500
- }
501
- info->rd_waiter_.broadcast();
502
- return true;
503
- };
504
- }, h, data, size);
505
- }
506
-
507
- static bool try_send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
508
- return send([tm](auto info, auto que, auto msg_id) {
509
- return [tm, info, que, msg_id](std::int32_t remain, void const * data, std::size_t size) {
510
- if (!wait_for(info->wt_waiter_, [&] {
511
- return !que->push(
512
- [](void*) { return true; },
513
- info->cc_id_, msg_id, remain, data, size);
514
- }, tm)) {
515
- return false;
516
- }
517
- info->rd_waiter_.broadcast();
518
- return true;
519
- };
520
- }, h, data, size);
521
- }
522
-
523
- static ipc::buff_t recv(ipc::handle_t h, std::uint64_t tm) {
524
- auto que = queue_of(h);
525
- if (que == nullptr) {
526
- ipc::error("fail: recv, queue_of(h) == nullptr\n");
527
- return {};
528
- }
529
- if (!que->connected()) {
530
- // hasn't connected yet, just return.
531
- return {};
532
- }
533
- auto& rc = info_of(h)->recv_cache();
534
- for (;;) {
535
- // pop a new message
536
- typename queue_t::value_t msg;
537
- if (!wait_for(info_of(h)->rd_waiter_, [que, &msg] {
538
- return !que->pop(msg);
539
- }, tm)) {
540
- // pop failed, just return.
541
- return {};
542
- }
543
- info_of(h)->wt_waiter_.broadcast();
544
- if ((info_of(h)->acc() != nullptr) && (msg.cc_id_ == info_of(h)->cc_id_)) {
545
- continue; // ignore message to self
546
- }
547
- // msg.remain_ may minus & abs(msg.remain_) < data_length
548
- std::int32_t r_size = static_cast<std::int32_t>(ipc::data_length) + msg.remain_;
549
- if (r_size <= 0) {
550
- ipc::error("fail: recv, r_size = %d\n", (int)r_size);
551
- return {};
552
- }
553
- std::size_t msg_size = static_cast<std::size_t>(r_size);
554
- // large message
555
- if (msg.storage_) {
556
- ipc::storage_id_t buf_id = *reinterpret_cast<ipc::storage_id_t*>(&msg.data_);
557
- void* buf = find_storage(buf_id, msg_size);
558
- if (buf != nullptr) {
559
- struct recycle_t {
560
- ipc::storage_id_t storage_id;
561
- ipc::circ::cc_t curr_conns;
562
- ipc::circ::cc_t conn_id;
563
- } *r_info = ipc::mem::alloc<recycle_t>(recycle_t{
564
- buf_id, que->elems()->connections(std::memory_order_relaxed), que->connected_id()
565
- });
566
- if (r_info == nullptr) {
567
- ipc::log("fail: ipc::mem::alloc<recycle_t>.\n");
568
- return ipc::buff_t{buf, msg_size}; // no recycle
569
- } else {
570
- return ipc::buff_t{buf, msg_size, [](void* p_info, std::size_t size) {
571
- auto r_info = static_cast<recycle_t *>(p_info);
572
- IPC_UNUSED_ auto finally = ipc::guard([r_info] {
573
- ipc::mem::free(r_info);
574
- });
575
- recycle_storage<flag_t>(r_info->storage_id, size, r_info->curr_conns, r_info->conn_id);
576
- }, r_info};
577
- }
578
- } else {
579
- ipc::log("fail: shm::handle for large message. msg_id: %zd, buf_id: %zd, size: %zd\n", msg.id_, buf_id, msg_size);
580
- continue;
581
- }
582
- }
583
- // find cache with msg.id_
584
- auto cac_it = rc.find(msg.id_);
585
- if (cac_it == rc.end()) {
586
- if (msg_size <= ipc::data_length) {
587
- return make_cache(msg.data_, msg_size);
588
- }
589
- // gc
590
- if (rc.size() > 1024) {
591
- std::vector<msg_id_t> need_del;
592
- for (auto const & pair : rc) {
593
- auto cmp = std::minmax(msg.id_, pair.first);
594
- if (cmp.second - cmp.first > 8192) {
595
- need_del.push_back(pair.first);
596
- }
597
- }
598
- for (auto id : need_del) rc.erase(id);
599
- }
600
- // cache the first message fragment
601
- rc.emplace(msg.id_, cache_t { ipc::data_length, make_cache(msg.data_, msg_size) });
602
- }
603
- // has cached before this message
604
- else {
605
- auto& cac = cac_it->second;
606
- // this is the last message fragment
607
- if (msg.remain_ <= 0) {
608
- cac.append(&(msg.data_), msg_size);
609
- // finish this message, erase it from cache
610
- auto buff = std::move(cac.buff_);
611
- rc.erase(cac_it);
612
- return buff;
613
- }
614
- // there are remain datas after this message
615
- cac.append(&(msg.data_), ipc::data_length);
616
- }
617
- }
618
- }
619
-
620
- static ipc::buff_t try_recv(ipc::handle_t h) {
621
- return recv(h, 0);
622
- }
623
-
624
- }; // detail_impl<Policy>
625
-
626
- template <typename Flag>
627
- using policy_t = ipc::policy::choose<ipc::circ::elem_array, Flag>;
628
-
629
- } // internal-linkage
630
-
631
- namespace ipc {
632
-
633
- template <typename Flag>
634
- ipc::handle_t chan_impl<Flag>::inited() {
635
- ipc::detail::waiter::init();
636
- return nullptr;
637
- }
638
-
639
- template <typename Flag>
640
- bool chan_impl<Flag>::connect(ipc::handle_t * ph, char const * name, unsigned mode) {
641
- return detail_impl<policy_t<Flag>>::connect(ph, name, mode & receiver);
642
- }
643
-
644
- template <typename Flag>
645
- bool chan_impl<Flag>::reconnect(ipc::handle_t * ph, unsigned mode) {
646
- return detail_impl<policy_t<Flag>>::reconnect(ph, mode & receiver);
647
- }
648
-
649
- template <typename Flag>
650
- void chan_impl<Flag>::disconnect(ipc::handle_t h) {
651
- detail_impl<policy_t<Flag>>::disconnect(h);
652
- }
653
-
654
- template <typename Flag>
655
- void chan_impl<Flag>::destroy(ipc::handle_t h) {
656
- detail_impl<policy_t<Flag>>::destroy(h);
657
- }
658
-
659
- template <typename Flag>
660
- char const * chan_impl<Flag>::name(ipc::handle_t h) {
661
- auto info = detail_impl<policy_t<Flag>>::info_of(h);
662
- return (info == nullptr) ? nullptr : info->name_.c_str();
663
- }
664
-
665
- template <typename Flag>
666
- std::size_t chan_impl<Flag>::recv_count(ipc::handle_t h) {
667
- return detail_impl<policy_t<Flag>>::recv_count(h);
668
- }
669
-
670
- template <typename Flag>
671
- bool chan_impl<Flag>::wait_for_recv(ipc::handle_t h, std::size_t r_count, std::uint64_t tm) {
672
- return detail_impl<policy_t<Flag>>::wait_for_recv(h, r_count, tm);
673
- }
674
-
675
- template <typename Flag>
676
- bool chan_impl<Flag>::send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
677
- return detail_impl<policy_t<Flag>>::send(h, data, size, tm);
678
- }
679
-
680
- template <typename Flag>
681
- buff_t chan_impl<Flag>::recv(ipc::handle_t h, std::uint64_t tm) {
682
- return detail_impl<policy_t<Flag>>::recv(h, tm);
683
- }
684
-
685
- template <typename Flag>
686
- bool chan_impl<Flag>::try_send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
687
- return detail_impl<policy_t<Flag>>::try_send(h, data, size, tm);
688
- }
689
-
690
- template <typename Flag>
691
- buff_t chan_impl<Flag>::try_recv(ipc::handle_t h) {
692
- return detail_impl<policy_t<Flag>>::try_recv(h);
693
- }
694
-
695
- template struct chan_impl<ipc::wr<relat::single, relat::single, trans::unicast >>;
696
- // template struct chan_impl<ipc::wr<relat::single, relat::multi , trans::unicast >>; // TBD
697
- // template struct chan_impl<ipc::wr<relat::multi , relat::multi , trans::unicast >>; // TBD
698
- template struct chan_impl<ipc::wr<relat::single, relat::multi , trans::broadcast>>;
699
- template struct chan_impl<ipc::wr<relat::multi , relat::multi , trans::broadcast>>;
700
-
701
- } // namespace ipc
 
1
+
2
+ #include <type_traits>
3
+ #include <cstring>
4
+ #include <algorithm>
5
+ #include <utility> // std::pair, std::move, std::forward
6
+ #include <atomic>
7
+ #include <type_traits> // aligned_storage_t
8
+ #include <string>
9
+ #include <vector>
10
+ #include <array>
11
+ #include <cassert>
12
+
13
+ #include "libipc/ipc.h"
14
+ #include "libipc/def.h"
15
+ #include "libipc/shm.h"
16
+ #include "libipc/pool_alloc.h"
17
+ #include "libipc/queue.h"
18
+ #include "libipc/policy.h"
19
+ #include "libipc/rw_lock.h"
20
+ #include "libipc/waiter.h"
21
+
22
+ #include "libipc/utility/log.h"
23
+ #include "libipc/utility/id_pool.h"
24
+ #include "libipc/utility/scope_guard.h"
25
+ #include "libipc/utility/utility.h"
26
+
27
+ #include "libipc/memory/resource.h"
28
+ #include "libipc/platform/detail.h"
29
+ #include "libipc/circ/elem_array.h"
30
+
31
+ namespace {
32
+
33
+ using msg_id_t = std::uint32_t;
34
+ using acc_t = std::atomic<msg_id_t>;
35
+
36
+ template <std::size_t DataSize, std::size_t AlignSize>
37
+ struct msg_t;
38
+
39
+ template <std::size_t AlignSize>
40
+ struct msg_t<0, AlignSize> {
41
+ msg_id_t cc_id_;
42
+ msg_id_t id_;
43
+ std::int32_t remain_;
44
+ bool storage_;
45
+ };
46
+
47
+ template <std::size_t DataSize, std::size_t AlignSize>
48
+ struct msg_t : msg_t<0, AlignSize> {
49
+ std::aligned_storage_t<DataSize, AlignSize> data_ {};
50
+
51
+ msg_t() = default;
52
+ msg_t(msg_id_t cc_id, msg_id_t id, std::int32_t remain, void const * data, std::size_t size)
53
+ : msg_t<0, AlignSize> {cc_id, id, remain, (data == nullptr) || (size == 0)} {
54
+ if (this->storage_) {
55
+ if (data != nullptr) {
56
+ // copy storage-id
57
+ *reinterpret_cast<ipc::storage_id_t*>(&data_) =
58
+ *static_cast<ipc::storage_id_t const *>(data);
59
+ }
60
+ }
61
+ else std::memcpy(&data_, data, size);
62
+ }
63
+ };
64
+
65
+ template <typename T>
66
+ ipc::buff_t make_cache(T& data, std::size_t size) {
67
+ auto ptr = ipc::mem::alloc(size);
68
+ std::memcpy(ptr, &data, (ipc::detail::min)(sizeof(data), size));
69
+ return { ptr, size, ipc::mem::free };
70
+ }
71
+
72
+ struct cache_t {
73
+ std::size_t fill_;
74
+ ipc::buff_t buff_;
75
+
76
+ cache_t(std::size_t f, ipc::buff_t && b)
77
+ : fill_(f), buff_(std::move(b))
78
+ {}
79
+
80
+ void append(void const * data, std::size_t size) {
81
+ if (fill_ >= buff_.size() || data == nullptr || size == 0) return;
82
+ auto new_fill = (ipc::detail::min)(fill_ + size, buff_.size());
83
+ std::memcpy(static_cast<ipc::byte_t*>(buff_.data()) + fill_, data, new_fill - fill_);
84
+ fill_ = new_fill;
85
+ }
86
+ };
87
+
88
+ auto cc_acc() {
89
+ static ipc::shm::handle acc_h("__CA_CONN__", sizeof(acc_t));
90
+ return static_cast<acc_t*>(acc_h.get());
91
+ }
92
+
93
+ IPC_CONSTEXPR_ std::size_t align_chunk_size(std::size_t size) noexcept {
94
+ return (((size - 1) / ipc::large_msg_align) + 1) * ipc::large_msg_align;
95
+ }
96
+
97
+ IPC_CONSTEXPR_ std::size_t calc_chunk_size(std::size_t size) noexcept {
98
+ return ipc::make_align(alignof(std::max_align_t), align_chunk_size(
99
+ ipc::make_align(alignof(std::max_align_t), sizeof(std::atomic<ipc::circ::cc_t>)) + size));
100
+ }
101
+
102
+ struct chunk_t {
103
+ std::atomic<ipc::circ::cc_t> &conns() noexcept {
104
+ return *reinterpret_cast<std::atomic<ipc::circ::cc_t> *>(this);
105
+ }
106
+
107
+ void *data() noexcept {
108
+ return reinterpret_cast<ipc::byte_t *>(this)
109
+ + ipc::make_align(alignof(std::max_align_t), sizeof(std::atomic<ipc::circ::cc_t>));
110
+ }
111
+ };
112
+
113
+ struct chunk_info_t {
114
+ ipc::id_pool<> pool_;
115
+ ipc::spin_lock lock_;
116
+
117
+ IPC_CONSTEXPR_ static std::size_t chunks_mem_size(std::size_t chunk_size) noexcept {
118
+ return ipc::id_pool<>::max_count * chunk_size;
119
+ }
120
+
121
+ ipc::byte_t *chunks_mem() noexcept {
122
+ return reinterpret_cast<ipc::byte_t *>(this + 1);
123
+ }
124
+
125
+ chunk_t *at(std::size_t chunk_size, ipc::storage_id_t id) noexcept {
126
+ if (id < 0) return nullptr;
127
+ return reinterpret_cast<chunk_t *>(chunks_mem() + (chunk_size * id));
128
+ }
129
+ };
130
+
131
+ auto& chunk_storages() {
132
+ class chunk_handle_t {
133
+ ipc::shm::handle handle_;
134
+
135
+ public:
136
+ chunk_info_t *get_info(std::size_t chunk_size) {
137
+ if (!handle_.valid() &&
138
+ !handle_.acquire( ("__CHUNK_INFO__" + ipc::to_string(chunk_size)).c_str(),
139
+ sizeof(chunk_info_t) + chunk_info_t::chunks_mem_size(chunk_size) )) {
140
+ ipc::error("[chunk_storages] chunk_shm.id_info_.acquire failed: chunk_size = %zd\n", chunk_size);
141
+ return nullptr;
142
+ }
143
+ auto info = static_cast<chunk_info_t*>(handle_.get());
144
+ if (info == nullptr) {
145
+ ipc::error("[chunk_storages] chunk_shm.id_info_.get failed: chunk_size = %zd\n", chunk_size);
146
+ return nullptr;
147
+ }
148
+ return info;
149
+ }
150
+ };
151
+ static ipc::map<std::size_t, chunk_handle_t> chunk_hs;
152
+ return chunk_hs;
153
+ }
154
+
155
+ chunk_info_t *chunk_storage_info(std::size_t chunk_size) {
156
+ auto &storages = chunk_storages();
157
+ std::decay_t<decltype(storages)>::iterator it;
158
+ {
159
+ static ipc::rw_lock lock;
160
+ IPC_UNUSED_ std::shared_lock<ipc::rw_lock> guard {lock};
161
+ if ((it = storages.find(chunk_size)) == storages.end()) {
162
+ using chunk_handle_t = std::decay_t<decltype(storages)>::value_type::second_type;
163
+ guard.unlock();
164
+ IPC_UNUSED_ std::lock_guard<ipc::rw_lock> guard {lock};
165
+ it = storages.emplace(chunk_size, chunk_handle_t{}).first;
166
+ }
167
+ }
168
+ return it->second.get_info(chunk_size);
169
+ }
170
+
171
+ std::pair<ipc::storage_id_t, void*> acquire_storage(std::size_t size, ipc::circ::cc_t conns) {
172
+ std::size_t chunk_size = calc_chunk_size(size);
173
+ auto info = chunk_storage_info(chunk_size);
174
+ if (info == nullptr) return {};
175
+
176
+ info->lock_.lock();
177
+ info->pool_.prepare();
178
+ // got an unique id
179
+ auto id = info->pool_.acquire();
180
+ info->lock_.unlock();
181
+
182
+ auto chunk = info->at(chunk_size, id);
183
+ if (chunk == nullptr) return {};
184
+ chunk->conns().store(conns, std::memory_order_relaxed);
185
+ return { id, chunk->data() };
186
+ }
187
+
188
+ void *find_storage(ipc::storage_id_t id, std::size_t size) {
189
+ if (id < 0) {
190
+ ipc::error("[find_storage] id is invalid: id = %ld, size = %zd\n", (long)id, size);
191
+ return nullptr;
192
+ }
193
+ std::size_t chunk_size = calc_chunk_size(size);
194
+ auto info = chunk_storage_info(chunk_size);
195
+ if (info == nullptr) return nullptr;
196
+ return info->at(chunk_size, id)->data();
197
+ }
198
+
199
+ void release_storage(ipc::storage_id_t id, std::size_t size) {
200
+ if (id < 0) {
201
+ ipc::error("[release_storage] id is invalid: id = %ld, size = %zd\n", (long)id, size);
202
+ return;
203
+ }
204
+ std::size_t chunk_size = calc_chunk_size(size);
205
+ auto info = chunk_storage_info(chunk_size);
206
+ if (info == nullptr) return;
207
+ info->lock_.lock();
208
+ info->pool_.release(id);
209
+ info->lock_.unlock();
210
+ }
211
+
212
+ template <ipc::relat Rp, ipc::relat Rc>
213
+ bool sub_rc(ipc::wr<Rp, Rc, ipc::trans::unicast>,
214
+ std::atomic<ipc::circ::cc_t> &/*conns*/, ipc::circ::cc_t /*curr_conns*/, ipc::circ::cc_t /*conn_id*/) noexcept {
215
+ return true;
216
+ }
217
+
218
+ template <ipc::relat Rp, ipc::relat Rc>
219
+ bool sub_rc(ipc::wr<Rp, Rc, ipc::trans::broadcast>,
220
+ std::atomic<ipc::circ::cc_t> &conns, ipc::circ::cc_t curr_conns, ipc::circ::cc_t conn_id) noexcept {
221
+ auto last_conns = curr_conns & ~conn_id;
222
+ for (unsigned k = 0;;) {
223
+ auto chunk_conns = conns.load(std::memory_order_acquire);
224
+ if (conns.compare_exchange_weak(chunk_conns, chunk_conns & last_conns, std::memory_order_release)) {
225
+ return (chunk_conns & last_conns) == 0;
226
+ }
227
+ ipc::yield(k);
228
+ }
229
+ }
230
+
231
+ template <typename Flag>
232
+ void recycle_storage(ipc::storage_id_t id, std::size_t size, ipc::circ::cc_t curr_conns, ipc::circ::cc_t conn_id) {
233
+ if (id < 0) {
234
+ ipc::error("[recycle_storage] id is invalid: id = %ld, size = %zd\n", (long)id, size);
235
+ return;
236
+ }
237
+ std::size_t chunk_size = calc_chunk_size(size);
238
+ auto info = chunk_storage_info(chunk_size);
239
+ if (info == nullptr) return;
240
+
241
+ auto chunk = info->at(chunk_size, id);
242
+ if (chunk == nullptr) return;
243
+
244
+ if (!sub_rc(Flag{}, chunk->conns(), curr_conns, conn_id)) {
245
+ return;
246
+ }
247
+ info->lock_.lock();
248
+ info->pool_.release(id);
249
+ info->lock_.unlock();
250
+ }
251
+
252
+ template <typename MsgT>
253
+ bool clear_message(void* p) {
254
+ auto msg = static_cast<MsgT*>(p);
255
+ if (msg->storage_) {
256
+ std::int32_t r_size = static_cast<std::int32_t>(ipc::data_length) + msg->remain_;
257
+ if (r_size <= 0) {
258
+ ipc::error("[clear_message] invalid msg size: %d\n", (int)r_size);
259
+ return true;
260
+ }
261
+ release_storage(
262
+ *reinterpret_cast<ipc::storage_id_t*>(&msg->data_),
263
+ static_cast<std::size_t>(r_size));
264
+ }
265
+ return true;
266
+ }
267
+
268
+ struct conn_info_head {
269
+
270
+ ipc::string name_;
271
+ msg_id_t cc_id_; // connection-info id
272
+ ipc::detail::waiter cc_waiter_, wt_waiter_, rd_waiter_;
273
+ ipc::shm::handle acc_h_;
274
+
275
+ conn_info_head(char const * name)
276
+ : name_ {name}
277
+ , cc_id_ {(cc_acc() == nullptr) ? 0 : cc_acc()->fetch_add(1, std::memory_order_relaxed)}
278
+ , cc_waiter_{("__CC_CONN__" + name_).c_str()}
279
+ , wt_waiter_{("__WT_CONN__" + name_).c_str()}
280
+ , rd_waiter_{("__RD_CONN__" + name_).c_str()}
281
+ , acc_h_ {("__AC_CONN__" + name_).c_str(), sizeof(acc_t)} {
282
+ }
283
+
284
+ void quit_waiting() {
285
+ cc_waiter_.quit_waiting();
286
+ wt_waiter_.quit_waiting();
287
+ rd_waiter_.quit_waiting();
288
+ }
289
+
290
+ auto acc() {
291
+ return static_cast<acc_t*>(acc_h_.get());
292
+ }
293
+
294
+ auto& recv_cache() {
295
+ thread_local ipc::unordered_map<msg_id_t, cache_t> tls;
296
+ return tls;
297
+ }
298
+ };
299
+
300
+ template <typename W, typename F>
301
+ bool wait_for(W& waiter, F&& pred, std::uint64_t tm) {
302
+ if (tm == 0) return !pred();
303
+ for (unsigned k = 0; pred();) {
304
+ bool ret = true;
305
+ ipc::sleep(k, [&k, &ret, &waiter, &pred, tm] {
306
+ ret = waiter.wait_if(std::forward<F>(pred), tm);
307
+ k = 0;
308
+ });
309
+ if (!ret) return false; // timeout or fail
310
+ if (k == 0) break; // k has been reset
311
+ }
312
+ return true;
313
+ }
314
+
315
+ template <typename Policy,
316
+ std::size_t DataSize = ipc::data_length,
317
+ std::size_t AlignSize = (ipc::detail::min)(DataSize, alignof(std::max_align_t))>
318
+ struct queue_generator {
319
+
320
+ using queue_t = ipc::queue<msg_t<DataSize, AlignSize>, Policy>;
321
+
322
+ struct conn_info_t : conn_info_head {
323
+ queue_t que_;
324
+
325
+ conn_info_t(char const * name)
326
+ : conn_info_head{name}
327
+ , que_{("__QU_CONN__" +
328
+ ipc::to_string(DataSize) + "__" +
329
+ ipc::to_string(AlignSize) + "__" + name).c_str()} {
330
+ }
331
+
332
+ void disconnect_receiver() {
333
+ bool dis = que_.disconnect();
334
+ this->quit_waiting();
335
+ if (dis) {
336
+ this->recv_cache().clear();
337
+ }
338
+ }
339
+ };
340
+ };
341
+
342
+ template <typename Policy>
343
+ struct detail_impl {
344
+
345
+ using policy_t = Policy;
346
+ using flag_t = typename policy_t::flag_t;
347
+ using queue_t = typename queue_generator<policy_t>::queue_t;
348
+ using conn_info_t = typename queue_generator<policy_t>::conn_info_t;
349
+
350
+ constexpr static conn_info_t* info_of(ipc::handle_t h) noexcept {
351
+ return static_cast<conn_info_t*>(h);
352
+ }
353
+
354
+ constexpr static queue_t* queue_of(ipc::handle_t h) noexcept {
355
+ return (info_of(h) == nullptr) ? nullptr : &(info_of(h)->que_);
356
+ }
357
+
358
+ /* API implementations */
359
+
360
+ static void disconnect(ipc::handle_t h) {
361
+ auto que = queue_of(h);
362
+ if (que == nullptr) {
363
+ return;
364
+ }
365
+ que->shut_sending();
366
+ assert(info_of(h) != nullptr);
367
+ info_of(h)->disconnect_receiver();
368
+ }
369
+
370
+ static bool reconnect(ipc::handle_t * ph, bool start_to_recv) {
371
+ assert(ph != nullptr);
372
+ assert(*ph != nullptr);
373
+ auto que = queue_of(*ph);
374
+ if (que == nullptr) {
375
+ return false;
376
+ }
377
+ if (start_to_recv) {
378
+ que->shut_sending();
379
+ if (que->connect()) { // wouldn't connect twice
380
+ info_of(*ph)->cc_waiter_.broadcast();
381
+ return true;
382
+ }
383
+ return false;
384
+ }
385
+ // start_to_recv == false
386
+ if (que->connected()) {
387
+ info_of(*ph)->disconnect_receiver();
388
+ }
389
+ return que->ready_sending();
390
+ }
391
+
392
+ static bool connect(ipc::handle_t * ph, char const * name, bool start_to_recv) {
393
+ assert(ph != nullptr);
394
+ if (*ph == nullptr) {
395
+ *ph = ipc::mem::alloc<conn_info_t>(name);
396
+ }
397
+ return reconnect(ph, start_to_recv);
398
+ }
399
+
400
+ static void destroy(ipc::handle_t h) {
401
+ disconnect(h);
402
+ ipc::mem::free(info_of(h));
403
+ }
404
+
405
+ static std::size_t recv_count(ipc::handle_t h) noexcept {
406
+ auto que = queue_of(h);
407
+ if (que == nullptr) {
408
+ return ipc::invalid_value;
409
+ }
410
+ return que->conn_count();
411
+ }
412
+
413
+ static bool wait_for_recv(ipc::handle_t h, std::size_t r_count, std::uint64_t tm) {
414
+ auto que = queue_of(h);
415
+ if (que == nullptr) {
416
+ return false;
417
+ }
418
+ return wait_for(info_of(h)->cc_waiter_, [que, r_count] {
419
+ return que->conn_count() < r_count;
420
+ }, tm);
421
+ }
422
+
423
+ template <typename F>
424
+ static bool send(F&& gen_push, ipc::handle_t h, void const * data, std::size_t size) {
425
+ if (data == nullptr || size == 0) {
426
+ ipc::error("fail: send(%p, %zd)\n", data, size);
427
+ return false;
428
+ }
429
+ auto que = queue_of(h);
430
+ if (que == nullptr) {
431
+ ipc::error("fail: send, queue_of(h) == nullptr\n");
432
+ return false;
433
+ }
434
+ if (que->elems() == nullptr) {
435
+ ipc::error("fail: send, queue_of(h)->elems() == nullptr\n");
436
+ return false;
437
+ }
438
+ if (!que->ready_sending()) {
439
+ ipc::error("fail: send, que->ready_sending() == false\n");
440
+ return false;
441
+ }
442
+ ipc::circ::cc_t conns = que->elems()->connections(std::memory_order_relaxed);
443
+ if (conns == 0) {
444
+ ipc::error("fail: send, there is no receiver on this connection.\n");
445
+ return false;
446
+ }
447
+ // calc a new message id
448
+ auto acc = info_of(h)->acc();
449
+ if (acc == nullptr) {
450
+ ipc::error("fail: send, info_of(h)->acc() == nullptr\n");
451
+ return false;
452
+ }
453
+ auto msg_id = acc->fetch_add(1, std::memory_order_relaxed);
454
+ auto try_push = std::forward<F>(gen_push)(info_of(h), que, msg_id);
455
+ if (size > ipc::large_msg_limit) {
456
+ auto dat = acquire_storage(size, conns);
457
+ void * buf = dat.second;
458
+ if (buf != nullptr) {
459
+ std::memcpy(buf, data, size);
460
+ return try_push(static_cast<std::int32_t>(size) -
461
+ static_cast<std::int32_t>(ipc::data_length), &(dat.first), 0);
462
+ }
463
+ // try using message fragment
464
+ //ipc::log("fail: shm::handle for big message. msg_id: %zd, size: %zd\n", msg_id, size);
465
+ }
466
+ // push message fragment
467
+ std::int32_t offset = 0;
468
+ for (std::int32_t i = 0; i < static_cast<std::int32_t>(size / ipc::data_length); ++i, offset += ipc::data_length) {
469
+ if (!try_push(static_cast<std::int32_t>(size) - offset - static_cast<std::int32_t>(ipc::data_length),
470
+ static_cast<ipc::byte_t const *>(data) + offset, ipc::data_length)) {
471
+ return false;
472
+ }
473
+ }
474
+ // if remain > 0, this is the last message fragment
475
+ std::int32_t remain = static_cast<std::int32_t>(size) - offset;
476
+ if (remain > 0) {
477
+ if (!try_push(remain - static_cast<std::int32_t>(ipc::data_length),
478
+ static_cast<ipc::byte_t const *>(data) + offset,
479
+ static_cast<std::size_t>(remain))) {
480
+ return false;
481
+ }
482
+ }
483
+ return true;
484
+ }
485
+
486
+ static bool send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
487
+ return send([tm](auto info, auto que, auto msg_id) {
488
+ return [tm, info, que, msg_id](std::int32_t remain, void const * data, std::size_t size) {
489
+ if (!wait_for(info->wt_waiter_, [&] {
490
+ return !que->push(
491
+ [](void*) { return true; },
492
+ info->cc_id_, msg_id, remain, data, size);
493
+ }, tm)) {
494
+ ipc::log("force_push: msg_id = %zd, remain = %d, size = %zd\n", msg_id, remain, size);
495
+ if (!que->force_push(
496
+ clear_message<typename queue_t::value_t>,
497
+ info->cc_id_, msg_id, remain, data, size)) {
498
+ return false;
499
+ }
500
+ }
501
+ info->rd_waiter_.broadcast();
502
+ return true;
503
+ };
504
+ }, h, data, size);
505
+ }
506
+
507
+ static bool try_send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
508
+ return send([tm](auto info, auto que, auto msg_id) {
509
+ return [tm, info, que, msg_id](std::int32_t remain, void const * data, std::size_t size) {
510
+ if (!wait_for(info->wt_waiter_, [&] {
511
+ return !que->push(
512
+ [](void*) { return true; },
513
+ info->cc_id_, msg_id, remain, data, size);
514
+ }, tm)) {
515
+ return false;
516
+ }
517
+ info->rd_waiter_.broadcast();
518
+ return true;
519
+ };
520
+ }, h, data, size);
521
+ }
522
+
523
+ static ipc::buff_t recv(ipc::handle_t h, std::uint64_t tm) {
524
+ auto que = queue_of(h);
525
+ if (que == nullptr) {
526
+ ipc::error("fail: recv, queue_of(h) == nullptr\n");
527
+ return {};
528
+ }
529
+ if (!que->connected()) {
530
+ // hasn't connected yet, just return.
531
+ return {};
532
+ }
533
+ auto& rc = info_of(h)->recv_cache();
534
+ for (;;) {
535
+ // pop a new message
536
+ typename queue_t::value_t msg;
537
+ if (!wait_for(info_of(h)->rd_waiter_, [que, &msg] {
538
+ return !que->pop(msg);
539
+ }, tm)) {
540
+ // pop failed, just return.
541
+ return {};
542
+ }
543
+ info_of(h)->wt_waiter_.broadcast();
544
+ if ((info_of(h)->acc() != nullptr) && (msg.cc_id_ == info_of(h)->cc_id_)) {
545
+ continue; // ignore message to self
546
+ }
547
+ // msg.remain_ may minus & abs(msg.remain_) < data_length
548
+ std::int32_t r_size = static_cast<std::int32_t>(ipc::data_length) + msg.remain_;
549
+ if (r_size <= 0) {
550
+ ipc::error("fail: recv, r_size = %d\n", (int)r_size);
551
+ return {};
552
+ }
553
+ std::size_t msg_size = static_cast<std::size_t>(r_size);
554
+ // large message
555
+ if (msg.storage_) {
556
+ ipc::storage_id_t buf_id = *reinterpret_cast<ipc::storage_id_t*>(&msg.data_);
557
+ void* buf = find_storage(buf_id, msg_size);
558
+ if (buf != nullptr) {
559
+ struct recycle_t {
560
+ ipc::storage_id_t storage_id;
561
+ ipc::circ::cc_t curr_conns;
562
+ ipc::circ::cc_t conn_id;
563
+ } *r_info = ipc::mem::alloc<recycle_t>(recycle_t{
564
+ buf_id, que->elems()->connections(std::memory_order_relaxed), que->connected_id()
565
+ });
566
+ if (r_info == nullptr) {
567
+ ipc::log("fail: ipc::mem::alloc<recycle_t>.\n");
568
+ return ipc::buff_t{buf, msg_size}; // no recycle
569
+ } else {
570
+ return ipc::buff_t{buf, msg_size, [](void* p_info, std::size_t size) {
571
+ auto r_info = static_cast<recycle_t *>(p_info);
572
+ IPC_UNUSED_ auto finally = ipc::guard([r_info] {
573
+ ipc::mem::free(r_info);
574
+ });
575
+ recycle_storage<flag_t>(r_info->storage_id, size, r_info->curr_conns, r_info->conn_id);
576
+ }, r_info};
577
+ }
578
+ } else {
579
+ ipc::log("fail: shm::handle for large message. msg_id: %zd, buf_id: %zd, size: %zd\n", msg.id_, buf_id, msg_size);
580
+ continue;
581
+ }
582
+ }
583
+ // find cache with msg.id_
584
+ auto cac_it = rc.find(msg.id_);
585
+ if (cac_it == rc.end()) {
586
+ if (msg_size <= ipc::data_length) {
587
+ return make_cache(msg.data_, msg_size);
588
+ }
589
+ // gc
590
+ if (rc.size() > 1024) {
591
+ std::vector<msg_id_t> need_del;
592
+ for (auto const & pair : rc) {
593
+ auto cmp = std::minmax(msg.id_, pair.first);
594
+ if (cmp.second - cmp.first > 8192) {
595
+ need_del.push_back(pair.first);
596
+ }
597
+ }
598
+ for (auto id : need_del) rc.erase(id);
599
+ }
600
+ // cache the first message fragment
601
+ rc.emplace(msg.id_, cache_t { ipc::data_length, make_cache(msg.data_, msg_size) });
602
+ }
603
+ // has cached before this message
604
+ else {
605
+ auto& cac = cac_it->second;
606
+ // this is the last message fragment
607
+ if (msg.remain_ <= 0) {
608
+ cac.append(&(msg.data_), msg_size);
609
+ // finish this message, erase it from cache
610
+ auto buff = std::move(cac.buff_);
611
+ rc.erase(cac_it);
612
+ return buff;
613
+ }
614
+ // there are remain datas after this message
615
+ cac.append(&(msg.data_), ipc::data_length);
616
+ }
617
+ }
618
+ }
619
+
620
+ static ipc::buff_t try_recv(ipc::handle_t h) {
621
+ return recv(h, 0);
622
+ }
623
+
624
+ }; // detail_impl<Policy>
625
+
626
+ template <typename Flag>
627
+ using policy_t = ipc::policy::choose<ipc::circ::elem_array, Flag>;
628
+
629
+ } // internal-linkage
630
+
631
+ namespace ipc {
632
+
633
+ template <typename Flag>
634
+ ipc::handle_t chan_impl<Flag>::inited() {
635
+ ipc::detail::waiter::init();
636
+ return nullptr;
637
+ }
638
+
639
+ template <typename Flag>
640
+ bool chan_impl<Flag>::connect(ipc::handle_t * ph, char const * name, unsigned mode) {
641
+ return detail_impl<policy_t<Flag>>::connect(ph, name, mode & receiver);
642
+ }
643
+
644
+ template <typename Flag>
645
+ bool chan_impl<Flag>::reconnect(ipc::handle_t * ph, unsigned mode) {
646
+ return detail_impl<policy_t<Flag>>::reconnect(ph, mode & receiver);
647
+ }
648
+
649
+ template <typename Flag>
650
+ void chan_impl<Flag>::disconnect(ipc::handle_t h) {
651
+ detail_impl<policy_t<Flag>>::disconnect(h);
652
+ }
653
+
654
+ template <typename Flag>
655
+ void chan_impl<Flag>::destroy(ipc::handle_t h) {
656
+ detail_impl<policy_t<Flag>>::destroy(h);
657
+ }
658
+
659
+ template <typename Flag>
660
+ char const * chan_impl<Flag>::name(ipc::handle_t h) {
661
+ auto info = detail_impl<policy_t<Flag>>::info_of(h);
662
+ return (info == nullptr) ? nullptr : info->name_.c_str();
663
+ }
664
+
665
+ template <typename Flag>
666
+ std::size_t chan_impl<Flag>::recv_count(ipc::handle_t h) {
667
+ return detail_impl<policy_t<Flag>>::recv_count(h);
668
+ }
669
+
670
+ template <typename Flag>
671
+ bool chan_impl<Flag>::wait_for_recv(ipc::handle_t h, std::size_t r_count, std::uint64_t tm) {
672
+ return detail_impl<policy_t<Flag>>::wait_for_recv(h, r_count, tm);
673
+ }
674
+
675
+ template <typename Flag>
676
+ bool chan_impl<Flag>::send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
677
+ return detail_impl<policy_t<Flag>>::send(h, data, size, tm);
678
+ }
679
+
680
+ template <typename Flag>
681
+ buff_t chan_impl<Flag>::recv(ipc::handle_t h, std::uint64_t tm) {
682
+ return detail_impl<policy_t<Flag>>::recv(h, tm);
683
+ }
684
+
685
+ template <typename Flag>
686
+ bool chan_impl<Flag>::try_send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm) {
687
+ return detail_impl<policy_t<Flag>>::try_send(h, data, size, tm);
688
+ }
689
+
690
+ template <typename Flag>
691
+ buff_t chan_impl<Flag>::try_recv(ipc::handle_t h) {
692
+ return detail_impl<policy_t<Flag>>::try_recv(h);
693
+ }
694
+
695
+ template struct chan_impl<ipc::wr<relat::single, relat::single, trans::unicast >>;
696
+ // template struct chan_impl<ipc::wr<relat::single, relat::multi , trans::unicast >>; // TBD
697
+ // template struct chan_impl<ipc::wr<relat::multi , relat::multi , trans::unicast >>; // TBD
698
+ template struct chan_impl<ipc::wr<relat::single, relat::multi , trans::broadcast>>;
699
+ template struct chan_impl<ipc::wr<relat::multi , relat::multi , trans::broadcast>>;
700
+
701
+ } // namespace ipc
crazy_functions/test_project/cpp/cppipc/policy.h CHANGED
@@ -1,25 +1,25 @@
1
- #pragma once
2
-
3
- #include <type_traits>
4
-
5
- #include "libipc/def.h"
6
- #include "libipc/prod_cons.h"
7
-
8
- #include "libipc/circ/elem_array.h"
9
-
10
- namespace ipc {
11
- namespace policy {
12
-
13
- template <template <typename, std::size_t...> class Elems, typename Flag>
14
- struct choose;
15
-
16
- template <typename Flag>
17
- struct choose<circ::elem_array, Flag> {
18
- using flag_t = Flag;
19
-
20
- template <std::size_t DataSize, std::size_t AlignSize>
21
- using elems_t = circ::elem_array<ipc::prod_cons_impl<flag_t>, DataSize, AlignSize>;
22
- };
23
-
24
- } // namespace policy
25
- } // namespace ipc
 
1
+ #pragma once
2
+
3
+ #include <type_traits>
4
+
5
+ #include "libipc/def.h"
6
+ #include "libipc/prod_cons.h"
7
+
8
+ #include "libipc/circ/elem_array.h"
9
+
10
+ namespace ipc {
11
+ namespace policy {
12
+
13
+ template <template <typename, std::size_t...> class Elems, typename Flag>
14
+ struct choose;
15
+
16
+ template <typename Flag>
17
+ struct choose<circ::elem_array, Flag> {
18
+ using flag_t = Flag;
19
+
20
+ template <std::size_t DataSize, std::size_t AlignSize>
21
+ using elems_t = circ::elem_array<ipc::prod_cons_impl<flag_t>, DataSize, AlignSize>;
22
+ };
23
+
24
+ } // namespace policy
25
+ } // namespace ipc
crazy_functions/test_project/cpp/cppipc/pool_alloc.cpp CHANGED
@@ -1,17 +1,17 @@
1
- #include "libipc/pool_alloc.h"
2
-
3
- #include "libipc/memory/resource.h"
4
-
5
- namespace ipc {
6
- namespace mem {
7
-
8
- void* pool_alloc::alloc(std::size_t size) {
9
- return async_pool_alloc::alloc(size);
10
- }
11
-
12
- void pool_alloc::free(void* p, std::size_t size) {
13
- async_pool_alloc::free(p, size);
14
- }
15
-
16
- } // namespace mem
17
- } // namespace ipc
 
1
+ #include "libipc/pool_alloc.h"
2
+
3
+ #include "libipc/memory/resource.h"
4
+
5
+ namespace ipc {
6
+ namespace mem {
7
+
8
+ void* pool_alloc::alloc(std::size_t size) {
9
+ return async_pool_alloc::alloc(size);
10
+ }
11
+
12
+ void pool_alloc::free(void* p, std::size_t size) {
13
+ async_pool_alloc::free(p, size);
14
+ }
15
+
16
+ } // namespace mem
17
+ } // namespace ipc
crazy_functions/test_project/cpp/cppipc/prod_cons.h CHANGED
@@ -1,433 +1,433 @@
1
- #pragma once
2
-
3
- #include <atomic>
4
- #include <utility>
5
- #include <cstring>
6
- #include <type_traits>
7
- #include <cstdint>
8
-
9
- #include "libipc/def.h"
10
-
11
- #include "libipc/platform/detail.h"
12
- #include "libipc/circ/elem_def.h"
13
- #include "libipc/utility/log.h"
14
- #include "libipc/utility/utility.h"
15
-
16
- namespace ipc {
17
-
18
- ////////////////////////////////////////////////////////////////
19
- /// producer-consumer implementation
20
- ////////////////////////////////////////////////////////////////
21
-
22
- template <typename Flag>
23
- struct prod_cons_impl;
24
-
25
- template <>
26
- struct prod_cons_impl<wr<relat::single, relat::single, trans::unicast>> {
27
-
28
- template <std::size_t DataSize, std::size_t AlignSize>
29
- struct elem_t {
30
- std::aligned_storage_t<DataSize, AlignSize> data_ {};
31
- };
32
-
33
- alignas(cache_line_size) std::atomic<circ::u2_t> rd_; // read index
34
- alignas(cache_line_size) std::atomic<circ::u2_t> wt_; // write index
35
-
36
- constexpr circ::u2_t cursor() const noexcept {
37
- return 0;
38
- }
39
-
40
- template <typename W, typename F, typename E>
41
- bool push(W* /*wrapper*/, F&& f, E* elems) {
42
- auto cur_wt = circ::index_of(wt_.load(std::memory_order_relaxed));
43
- if (cur_wt == circ::index_of(rd_.load(std::memory_order_acquire) - 1)) {
44
- return false; // full
45
- }
46
- std::forward<F>(f)(&(elems[cur_wt].data_));
47
- wt_.fetch_add(1, std::memory_order_release);
48
- return true;
49
- }
50
-
51
- /**
52
- * In single-single-unicast, 'force_push' means 'no reader' or 'the only one reader is dead'.
53
- * So we could just disconnect all connections of receiver, and return false.
54
- */
55
- template <typename W, typename F, typename E>
56
- bool force_push(W* wrapper, F&&, E*) {
57
- wrapper->elems()->disconnect_receiver(~static_cast<circ::cc_t>(0u));
58
- return false;
59
- }
60
-
61
- template <typename W, typename F, typename R, typename E>
62
- bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E* elems) {
63
- auto cur_rd = circ::index_of(rd_.load(std::memory_order_relaxed));
64
- if (cur_rd == circ::index_of(wt_.load(std::memory_order_acquire))) {
65
- return false; // empty
66
- }
67
- std::forward<F>(f)(&(elems[cur_rd].data_));
68
- std::forward<R>(out)(true);
69
- rd_.fetch_add(1, std::memory_order_release);
70
- return true;
71
- }
72
- };
73
-
74
- template <>
75
- struct prod_cons_impl<wr<relat::single, relat::multi , trans::unicast>>
76
- : prod_cons_impl<wr<relat::single, relat::single, trans::unicast>> {
77
-
78
- template <typename W, typename F, typename E>
79
- bool force_push(W* wrapper, F&&, E*) {
80
- wrapper->elems()->disconnect_receiver(1);
81
- return false;
82
- }
83
-
84
- template <typename W, typename F, typename R,
85
- template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
86
- bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E<DS, AS>* elems) {
87
- byte_t buff[DS];
88
- for (unsigned k = 0;;) {
89
- auto cur_rd = rd_.load(std::memory_order_relaxed);
90
- if (circ::index_of(cur_rd) ==
91
- circ::index_of(wt_.load(std::memory_order_acquire))) {
92
- return false; // empty
93
- }
94
- std::memcpy(buff, &(elems[circ::index_of(cur_rd)].data_), sizeof(buff));
95
- if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
96
- std::forward<F>(f)(buff);
97
- std::forward<R>(out)(true);
98
- return true;
99
- }
100
- ipc::yield(k);
101
- }
102
- }
103
- };
104
-
105
- template <>
106
- struct prod_cons_impl<wr<relat::multi , relat::multi, trans::unicast>>
107
- : prod_cons_impl<wr<relat::single, relat::multi, trans::unicast>> {
108
-
109
- using flag_t = std::uint64_t;
110
-
111
- template <std::size_t DataSize, std::size_t AlignSize>
112
- struct elem_t {
113
- std::aligned_storage_t<DataSize, AlignSize> data_ {};
114
- std::atomic<flag_t> f_ct_ { 0 }; // commit flag
115
- };
116
-
117
- alignas(cache_line_size) std::atomic<circ::u2_t> ct_; // commit index
118
-
119
- template <typename W, typename F, typename E>
120
- bool push(W* /*wrapper*/, F&& f, E* elems) {
121
- circ::u2_t cur_ct, nxt_ct;
122
- for (unsigned k = 0;;) {
123
- cur_ct = ct_.load(std::memory_order_relaxed);
124
- if (circ::index_of(nxt_ct = cur_ct + 1) ==
125
- circ::index_of(rd_.load(std::memory_order_acquire))) {
126
- return false; // full
127
- }
128
- if (ct_.compare_exchange_weak(cur_ct, nxt_ct, std::memory_order_acq_rel)) {
129
- break;
130
- }
131
- ipc::yield(k);
132
- }
133
- auto* el = elems + circ::index_of(cur_ct);
134
- std::forward<F>(f)(&(el->data_));
135
- // set flag & try update wt
136
- el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
137
- while (1) {
138
- auto cac_ct = el->f_ct_.load(std::memory_order_acquire);
139
- if (cur_ct != wt_.load(std::memory_order_relaxed)) {
140
- return true;
141
- }
142
- if ((~cac_ct) != cur_ct) {
143
- return true;
144
- }
145
- if (!el->f_ct_.compare_exchange_strong(cac_ct, 0, std::memory_order_relaxed)) {
146
- return true;
147
- }
148
- wt_.store(nxt_ct, std::memory_order_release);
149
- cur_ct = nxt_ct;
150
- nxt_ct = cur_ct + 1;
151
- el = elems + circ::index_of(cur_ct);
152
- }
153
- return true;
154
- }
155
-
156
- template <typename W, typename F, typename E>
157
- bool force_push(W* wrapper, F&&, E*) {
158
- wrapper->elems()->disconnect_receiver(1);
159
- return false;
160
- }
161
-
162
- template <typename W, typename F, typename R,
163
- template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
164
- bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E<DS, AS>* elems) {
165
- byte_t buff[DS];
166
- for (unsigned k = 0;;) {
167
- auto cur_rd = rd_.load(std::memory_order_relaxed);
168
- auto cur_wt = wt_.load(std::memory_order_acquire);
169
- auto id_rd = circ::index_of(cur_rd);
170
- auto id_wt = circ::index_of(cur_wt);
171
- if (id_rd == id_wt) {
172
- auto* el = elems + id_wt;
173
- auto cac_ct = el->f_ct_.load(std::memory_order_acquire);
174
- if ((~cac_ct) != cur_wt) {
175
- return false; // empty
176
- }
177
- if (el->f_ct_.compare_exchange_weak(cac_ct, 0, std::memory_order_relaxed)) {
178
- wt_.store(cur_wt + 1, std::memory_order_release);
179
- }
180
- k = 0;
181
- }
182
- else {
183
- std::memcpy(buff, &(elems[circ::index_of(cur_rd)].data_), sizeof(buff));
184
- if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
185
- std::forward<F>(f)(buff);
186
- std::forward<R>(out)(true);
187
- return true;
188
- }
189
- ipc::yield(k);
190
- }
191
- }
192
- }
193
- };
194
-
195
- template <>
196
- struct prod_cons_impl<wr<relat::single, relat::multi, trans::broadcast>> {
197
-
198
- using rc_t = std::uint64_t;
199
-
200
- enum : rc_t {
201
- ep_mask = 0x00000000ffffffffull,
202
- ep_incr = 0x0000000100000000ull
203
- };
204
-
205
- template <std::size_t DataSize, std::size_t AlignSize>
206
- struct elem_t {
207
- std::aligned_storage_t<DataSize, AlignSize> data_ {};
208
- std::atomic<rc_t> rc_ { 0 }; // read-counter
209
- };
210
-
211
- alignas(cache_line_size) std::atomic<circ::u2_t> wt_; // write index
212
- alignas(cache_line_size) rc_t epoch_ { 0 }; // only one writer
213
-
214
- circ::u2_t cursor() const noexcept {
215
- return wt_.load(std::memory_order_acquire);
216
- }
217
-
218
- template <typename W, typename F, typename E>
219
- bool push(W* wrapper, F&& f, E* elems) {
220
- E* el;
221
- for (unsigned k = 0;;) {
222
- circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
223
- if (cc == 0) return false; // no reader
224
- el = elems + circ::index_of(wt_.load(std::memory_order_relaxed));
225
- // check all consumers have finished reading this element
226
- auto cur_rc = el->rc_.load(std::memory_order_acquire);
227
- circ::cc_t rem_cc = cur_rc & ep_mask;
228
- if ((cc & rem_cc) && ((cur_rc & ~ep_mask) == epoch_)) {
229
- return false; // has not finished yet
230
- }
231
- // consider rem_cc to be 0 here
232
- if (el->rc_.compare_exchange_weak(
233
- cur_rc, epoch_ | static_cast<rc_t>(cc), std::memory_order_release)) {
234
- break;
235
- }
236
- ipc::yield(k);
237
- }
238
- std::forward<F>(f)(&(el->data_));
239
- wt_.fetch_add(1, std::memory_order_release);
240
- return true;
241
- }
242
-
243
- template <typename W, typename F, typename E>
244
- bool force_push(W* wrapper, F&& f, E* elems) {
245
- E* el;
246
- epoch_ += ep_incr;
247
- for (unsigned k = 0;;) {
248
- circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
249
- if (cc == 0) return false; // no reader
250
- el = elems + circ::index_of(wt_.load(std::memory_order_relaxed));
251
- // check all consumers have finished reading this element
252
- auto cur_rc = el->rc_.load(std::memory_order_acquire);
253
- circ::cc_t rem_cc = cur_rc & ep_mask;
254
- if (cc & rem_cc) {
255
- ipc::log("force_push: k = %u, cc = %u, rem_cc = %u\n", k, cc, rem_cc);
256
- cc = wrapper->elems()->disconnect_receiver(rem_cc); // disconnect all invalid readers
257
- if (cc == 0) return false; // no reader
258
- }
259
- // just compare & exchange
260
- if (el->rc_.compare_exchange_weak(
261
- cur_rc, epoch_ | static_cast<rc_t>(cc), std::memory_order_release)) {
262
- break;
263
- }
264
- ipc::yield(k);
265
- }
266
- std::forward<F>(f)(&(el->data_));
267
- wt_.fetch_add(1, std::memory_order_release);
268
- return true;
269
- }
270
-
271
- template <typename W, typename F, typename R, typename E>
272
- bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E* elems) {
273
- if (cur == cursor()) return false; // acquire
274
- auto* el = elems + circ::index_of(cur++);
275
- std::forward<F>(f)(&(el->data_));
276
- for (unsigned k = 0;;) {
277
- auto cur_rc = el->rc_.load(std::memory_order_acquire);
278
- if ((cur_rc & ep_mask) == 0) {
279
- std::forward<R>(out)(true);
280
- return true;
281
- }
282
- auto nxt_rc = cur_rc & ~static_cast<rc_t>(wrapper->connected_id());
283
- if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
284
- std::forward<R>(out)((nxt_rc & ep_mask) == 0);
285
- return true;
286
- }
287
- ipc::yield(k);
288
- }
289
- }
290
- };
291
-
292
- template <>
293
- struct prod_cons_impl<wr<relat::multi, relat::multi, trans::broadcast>> {
294
-
295
- using rc_t = std::uint64_t;
296
- using flag_t = std::uint64_t;
297
-
298
- enum : rc_t {
299
- rc_mask = 0x00000000ffffffffull,
300
- ep_mask = 0x00ffffffffffffffull,
301
- ep_incr = 0x0100000000000000ull,
302
- ic_mask = 0xff000000ffffffffull,
303
- ic_incr = 0x0000000100000000ull
304
- };
305
-
306
- template <std::size_t DataSize, std::size_t AlignSize>
307
- struct elem_t {
308
- std::aligned_storage_t<DataSize, AlignSize> data_ {};
309
- std::atomic<rc_t > rc_ { 0 }; // read-counter
310
- std::atomic<flag_t> f_ct_ { 0 }; // commit flag
311
- };
312
-
313
- alignas(cache_line_size) std::atomic<circ::u2_t> ct_; // commit index
314
- alignas(cache_line_size) std::atomic<rc_t> epoch_ { 0 };
315
-
316
- circ::u2_t cursor() const noexcept {
317
- return ct_.load(std::memory_order_acquire);
318
- }
319
-
320
- constexpr static rc_t inc_rc(rc_t rc) noexcept {
321
- return (rc & ic_mask) | ((rc + ic_incr) & ~ic_mask);
322
- }
323
-
324
- constexpr static rc_t inc_mask(rc_t rc) noexcept {
325
- return inc_rc(rc) & ~rc_mask;
326
- }
327
-
328
- template <typename W, typename F, typename E>
329
- bool push(W* wrapper, F&& f, E* elems) {
330
- E* el;
331
- circ::u2_t cur_ct;
332
- rc_t epoch = epoch_.load(std::memory_order_acquire);
333
- for (unsigned k = 0;;) {
334
- circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
335
- if (cc == 0) return false; // no reader
336
- el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
337
- // check all consumers have finished reading this element
338
- auto cur_rc = el->rc_.load(std::memory_order_relaxed);
339
- circ::cc_t rem_cc = cur_rc & rc_mask;
340
- if ((cc & rem_cc) && ((cur_rc & ~ep_mask) == epoch)) {
341
- return false; // has not finished yet
342
- }
343
- else if (!rem_cc) {
344
- auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
345
- if ((cur_fl != cur_ct) && cur_fl) {
346
- return false; // full
347
- }
348
- }
349
- // consider rem_cc to be 0 here
350
- if (el->rc_.compare_exchange_weak(
351
- cur_rc, inc_mask(epoch | (cur_rc & ep_mask)) | static_cast<rc_t>(cc), std::memory_order_relaxed) &&
352
- epoch_.compare_exchange_weak(epoch, epoch, std::memory_order_acq_rel)) {
353
- break;
354
- }
355
- ipc::yield(k);
356
- }
357
- // only one thread/process would touch here at one time
358
- ct_.store(cur_ct + 1, std::memory_order_release);
359
- std::forward<F>(f)(&(el->data_));
360
- // set flag & try update wt
361
- el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
362
- return true;
363
- }
364
-
365
- template <typename W, typename F, typename E>
366
- bool force_push(W* wrapper, F&& f, E* elems) {
367
- E* el;
368
- circ::u2_t cur_ct;
369
- rc_t epoch = epoch_.fetch_add(ep_incr, std::memory_order_release) + ep_incr;
370
- for (unsigned k = 0;;) {
371
- circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
372
- if (cc == 0) return false; // no reader
373
- el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
374
- // check all consumers have finished reading this element
375
- auto cur_rc = el->rc_.load(std::memory_order_acquire);
376
- circ::cc_t rem_cc = cur_rc & rc_mask;
377
- if (cc & rem_cc) {
378
- ipc::log("force_push: k = %u, cc = %u, rem_cc = %u\n", k, cc, rem_cc);
379
- cc = wrapper->elems()->disconnect_receiver(rem_cc); // disconnect all invalid readers
380
- if (cc == 0) return false; // no reader
381
- }
382
- // just compare & exchange
383
- if (el->rc_.compare_exchange_weak(
384
- cur_rc, inc_mask(epoch | (cur_rc & ep_mask)) | static_cast<rc_t>(cc), std::memory_order_relaxed)) {
385
- if (epoch == epoch_.load(std::memory_order_acquire)) {
386
- break;
387
- }
388
- else if (push(wrapper, std::forward<F>(f), elems)) {
389
- return true;
390
- }
391
- epoch = epoch_.fetch_add(ep_incr, std::memory_order_release) + ep_incr;
392
- }
393
- ipc::yield(k);
394
- }
395
- // only one thread/process would touch here at one time
396
- ct_.store(cur_ct + 1, std::memory_order_release);
397
- std::forward<F>(f)(&(el->data_));
398
- // set flag & try update wt
399
- el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
400
- return true;
401
- }
402
-
403
- template <typename W, typename F, typename R, typename E, std::size_t N>
404
- bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E(& elems)[N]) {
405
- auto* el = elems + circ::index_of(cur);
406
- auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
407
- if (cur_fl != ~static_cast<flag_t>(cur)) {
408
- return false; // empty
409
- }
410
- ++cur;
411
- std::forward<F>(f)(&(el->data_));
412
- for (unsigned k = 0;;) {
413
- auto cur_rc = el->rc_.load(std::memory_order_acquire);
414
- if ((cur_rc & rc_mask) == 0) {
415
- std::forward<R>(out)(true);
416
- el->f_ct_.store(cur + N - 1, std::memory_order_release);
417
- return true;
418
- }
419
- auto nxt_rc = inc_rc(cur_rc) & ~static_cast<rc_t>(wrapper->connected_id());
420
- bool last_one = false;
421
- if ((last_one = (nxt_rc & rc_mask) == 0)) {
422
- el->f_ct_.store(cur + N - 1, std::memory_order_release);
423
- }
424
- if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
425
- std::forward<R>(out)(last_one);
426
- return true;
427
- }
428
- ipc::yield(k);
429
- }
430
- }
431
- };
432
-
433
- } // namespace ipc
 
1
+ #pragma once
2
+
3
+ #include <atomic>
4
+ #include <utility>
5
+ #include <cstring>
6
+ #include <type_traits>
7
+ #include <cstdint>
8
+
9
+ #include "libipc/def.h"
10
+
11
+ #include "libipc/platform/detail.h"
12
+ #include "libipc/circ/elem_def.h"
13
+ #include "libipc/utility/log.h"
14
+ #include "libipc/utility/utility.h"
15
+
16
+ namespace ipc {
17
+
18
+ ////////////////////////////////////////////////////////////////
19
+ /// producer-consumer implementation
20
+ ////////////////////////////////////////////////////////////////
21
+
22
+ template <typename Flag>
23
+ struct prod_cons_impl;
24
+
25
+ template <>
26
+ struct prod_cons_impl<wr<relat::single, relat::single, trans::unicast>> {
27
+
28
+ template <std::size_t DataSize, std::size_t AlignSize>
29
+ struct elem_t {
30
+ std::aligned_storage_t<DataSize, AlignSize> data_ {};
31
+ };
32
+
33
+ alignas(cache_line_size) std::atomic<circ::u2_t> rd_; // read index
34
+ alignas(cache_line_size) std::atomic<circ::u2_t> wt_; // write index
35
+
36
+ constexpr circ::u2_t cursor() const noexcept {
37
+ return 0;
38
+ }
39
+
40
+ template <typename W, typename F, typename E>
41
+ bool push(W* /*wrapper*/, F&& f, E* elems) {
42
+ auto cur_wt = circ::index_of(wt_.load(std::memory_order_relaxed));
43
+ if (cur_wt == circ::index_of(rd_.load(std::memory_order_acquire) - 1)) {
44
+ return false; // full
45
+ }
46
+ std::forward<F>(f)(&(elems[cur_wt].data_));
47
+ wt_.fetch_add(1, std::memory_order_release);
48
+ return true;
49
+ }
50
+
51
+ /**
52
+ * In single-single-unicast, 'force_push' means 'no reader' or 'the only one reader is dead'.
53
+ * So we could just disconnect all connections of receiver, and return false.
54
+ */
55
+ template <typename W, typename F, typename E>
56
+ bool force_push(W* wrapper, F&&, E*) {
57
+ wrapper->elems()->disconnect_receiver(~static_cast<circ::cc_t>(0u));
58
+ return false;
59
+ }
60
+
61
+ template <typename W, typename F, typename R, typename E>
62
+ bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E* elems) {
63
+ auto cur_rd = circ::index_of(rd_.load(std::memory_order_relaxed));
64
+ if (cur_rd == circ::index_of(wt_.load(std::memory_order_acquire))) {
65
+ return false; // empty
66
+ }
67
+ std::forward<F>(f)(&(elems[cur_rd].data_));
68
+ std::forward<R>(out)(true);
69
+ rd_.fetch_add(1, std::memory_order_release);
70
+ return true;
71
+ }
72
+ };
73
+
74
+ template <>
75
+ struct prod_cons_impl<wr<relat::single, relat::multi , trans::unicast>>
76
+ : prod_cons_impl<wr<relat::single, relat::single, trans::unicast>> {
77
+
78
+ template <typename W, typename F, typename E>
79
+ bool force_push(W* wrapper, F&&, E*) {
80
+ wrapper->elems()->disconnect_receiver(1);
81
+ return false;
82
+ }
83
+
84
+ template <typename W, typename F, typename R,
85
+ template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
86
+ bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E<DS, AS>* elems) {
87
+ byte_t buff[DS];
88
+ for (unsigned k = 0;;) {
89
+ auto cur_rd = rd_.load(std::memory_order_relaxed);
90
+ if (circ::index_of(cur_rd) ==
91
+ circ::index_of(wt_.load(std::memory_order_acquire))) {
92
+ return false; // empty
93
+ }
94
+ std::memcpy(buff, &(elems[circ::index_of(cur_rd)].data_), sizeof(buff));
95
+ if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
96
+ std::forward<F>(f)(buff);
97
+ std::forward<R>(out)(true);
98
+ return true;
99
+ }
100
+ ipc::yield(k);
101
+ }
102
+ }
103
+ };
104
+
105
+ template <>
106
+ struct prod_cons_impl<wr<relat::multi , relat::multi, trans::unicast>>
107
+ : prod_cons_impl<wr<relat::single, relat::multi, trans::unicast>> {
108
+
109
+ using flag_t = std::uint64_t;
110
+
111
+ template <std::size_t DataSize, std::size_t AlignSize>
112
+ struct elem_t {
113
+ std::aligned_storage_t<DataSize, AlignSize> data_ {};
114
+ std::atomic<flag_t> f_ct_ { 0 }; // commit flag
115
+ };
116
+
117
+ alignas(cache_line_size) std::atomic<circ::u2_t> ct_; // commit index
118
+
119
+ template <typename W, typename F, typename E>
120
+ bool push(W* /*wrapper*/, F&& f, E* elems) {
121
+ circ::u2_t cur_ct, nxt_ct;
122
+ for (unsigned k = 0;;) {
123
+ cur_ct = ct_.load(std::memory_order_relaxed);
124
+ if (circ::index_of(nxt_ct = cur_ct + 1) ==
125
+ circ::index_of(rd_.load(std::memory_order_acquire))) {
126
+ return false; // full
127
+ }
128
+ if (ct_.compare_exchange_weak(cur_ct, nxt_ct, std::memory_order_acq_rel)) {
129
+ break;
130
+ }
131
+ ipc::yield(k);
132
+ }
133
+ auto* el = elems + circ::index_of(cur_ct);
134
+ std::forward<F>(f)(&(el->data_));
135
+ // set flag & try update wt
136
+ el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
137
+ while (1) {
138
+ auto cac_ct = el->f_ct_.load(std::memory_order_acquire);
139
+ if (cur_ct != wt_.load(std::memory_order_relaxed)) {
140
+ return true;
141
+ }
142
+ if ((~cac_ct) != cur_ct) {
143
+ return true;
144
+ }
145
+ if (!el->f_ct_.compare_exchange_strong(cac_ct, 0, std::memory_order_relaxed)) {
146
+ return true;
147
+ }
148
+ wt_.store(nxt_ct, std::memory_order_release);
149
+ cur_ct = nxt_ct;
150
+ nxt_ct = cur_ct + 1;
151
+ el = elems + circ::index_of(cur_ct);
152
+ }
153
+ return true;
154
+ }
155
+
156
+ template <typename W, typename F, typename E>
157
+ bool force_push(W* wrapper, F&&, E*) {
158
+ wrapper->elems()->disconnect_receiver(1);
159
+ return false;
160
+ }
161
+
162
+ template <typename W, typename F, typename R,
163
+ template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
164
+ bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E<DS, AS>* elems) {
165
+ byte_t buff[DS];
166
+ for (unsigned k = 0;;) {
167
+ auto cur_rd = rd_.load(std::memory_order_relaxed);
168
+ auto cur_wt = wt_.load(std::memory_order_acquire);
169
+ auto id_rd = circ::index_of(cur_rd);
170
+ auto id_wt = circ::index_of(cur_wt);
171
+ if (id_rd == id_wt) {
172
+ auto* el = elems + id_wt;
173
+ auto cac_ct = el->f_ct_.load(std::memory_order_acquire);
174
+ if ((~cac_ct) != cur_wt) {
175
+ return false; // empty
176
+ }
177
+ if (el->f_ct_.compare_exchange_weak(cac_ct, 0, std::memory_order_relaxed)) {
178
+ wt_.store(cur_wt + 1, std::memory_order_release);
179
+ }
180
+ k = 0;
181
+ }
182
+ else {
183
+ std::memcpy(buff, &(elems[circ::index_of(cur_rd)].data_), sizeof(buff));
184
+ if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
185
+ std::forward<F>(f)(buff);
186
+ std::forward<R>(out)(true);
187
+ return true;
188
+ }
189
+ ipc::yield(k);
190
+ }
191
+ }
192
+ }
193
+ };
194
+
195
+ template <>
196
+ struct prod_cons_impl<wr<relat::single, relat::multi, trans::broadcast>> {
197
+
198
+ using rc_t = std::uint64_t;
199
+
200
+ enum : rc_t {
201
+ ep_mask = 0x00000000ffffffffull,
202
+ ep_incr = 0x0000000100000000ull
203
+ };
204
+
205
+ template <std::size_t DataSize, std::size_t AlignSize>
206
+ struct elem_t {
207
+ std::aligned_storage_t<DataSize, AlignSize> data_ {};
208
+ std::atomic<rc_t> rc_ { 0 }; // read-counter
209
+ };
210
+
211
+ alignas(cache_line_size) std::atomic<circ::u2_t> wt_; // write index
212
+ alignas(cache_line_size) rc_t epoch_ { 0 }; // only one writer
213
+
214
+ circ::u2_t cursor() const noexcept {
215
+ return wt_.load(std::memory_order_acquire);
216
+ }
217
+
218
+ template <typename W, typename F, typename E>
219
+ bool push(W* wrapper, F&& f, E* elems) {
220
+ E* el;
221
+ for (unsigned k = 0;;) {
222
+ circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
223
+ if (cc == 0) return false; // no reader
224
+ el = elems + circ::index_of(wt_.load(std::memory_order_relaxed));
225
+ // check all consumers have finished reading this element
226
+ auto cur_rc = el->rc_.load(std::memory_order_acquire);
227
+ circ::cc_t rem_cc = cur_rc & ep_mask;
228
+ if ((cc & rem_cc) && ((cur_rc & ~ep_mask) == epoch_)) {
229
+ return false; // has not finished yet
230
+ }
231
+ // consider rem_cc to be 0 here
232
+ if (el->rc_.compare_exchange_weak(
233
+ cur_rc, epoch_ | static_cast<rc_t>(cc), std::memory_order_release)) {
234
+ break;
235
+ }
236
+ ipc::yield(k);
237
+ }
238
+ std::forward<F>(f)(&(el->data_));
239
+ wt_.fetch_add(1, std::memory_order_release);
240
+ return true;
241
+ }
242
+
243
+ template <typename W, typename F, typename E>
244
+ bool force_push(W* wrapper, F&& f, E* elems) {
245
+ E* el;
246
+ epoch_ += ep_incr;
247
+ for (unsigned k = 0;;) {
248
+ circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
249
+ if (cc == 0) return false; // no reader
250
+ el = elems + circ::index_of(wt_.load(std::memory_order_relaxed));
251
+ // check all consumers have finished reading this element
252
+ auto cur_rc = el->rc_.load(std::memory_order_acquire);
253
+ circ::cc_t rem_cc = cur_rc & ep_mask;
254
+ if (cc & rem_cc) {
255
+ ipc::log("force_push: k = %u, cc = %u, rem_cc = %u\n", k, cc, rem_cc);
256
+ cc = wrapper->elems()->disconnect_receiver(rem_cc); // disconnect all invalid readers
257
+ if (cc == 0) return false; // no reader
258
+ }
259
+ // just compare & exchange
260
+ if (el->rc_.compare_exchange_weak(
261
+ cur_rc, epoch_ | static_cast<rc_t>(cc), std::memory_order_release)) {
262
+ break;
263
+ }
264
+ ipc::yield(k);
265
+ }
266
+ std::forward<F>(f)(&(el->data_));
267
+ wt_.fetch_add(1, std::memory_order_release);
268
+ return true;
269
+ }
270
+
271
+ template <typename W, typename F, typename R, typename E>
272
+ bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E* elems) {
273
+ if (cur == cursor()) return false; // acquire
274
+ auto* el = elems + circ::index_of(cur++);
275
+ std::forward<F>(f)(&(el->data_));
276
+ for (unsigned k = 0;;) {
277
+ auto cur_rc = el->rc_.load(std::memory_order_acquire);
278
+ if ((cur_rc & ep_mask) == 0) {
279
+ std::forward<R>(out)(true);
280
+ return true;
281
+ }
282
+ auto nxt_rc = cur_rc & ~static_cast<rc_t>(wrapper->connected_id());
283
+ if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
284
+ std::forward<R>(out)((nxt_rc & ep_mask) == 0);
285
+ return true;
286
+ }
287
+ ipc::yield(k);
288
+ }
289
+ }
290
+ };
291
+
292
+ template <>
293
+ struct prod_cons_impl<wr<relat::multi, relat::multi, trans::broadcast>> {
294
+
295
+ using rc_t = std::uint64_t;
296
+ using flag_t = std::uint64_t;
297
+
298
+ enum : rc_t {
299
+ rc_mask = 0x00000000ffffffffull,
300
+ ep_mask = 0x00ffffffffffffffull,
301
+ ep_incr = 0x0100000000000000ull,
302
+ ic_mask = 0xff000000ffffffffull,
303
+ ic_incr = 0x0000000100000000ull
304
+ };
305
+
306
+ template <std::size_t DataSize, std::size_t AlignSize>
307
+ struct elem_t {
308
+ std::aligned_storage_t<DataSize, AlignSize> data_ {};
309
+ std::atomic<rc_t > rc_ { 0 }; // read-counter
310
+ std::atomic<flag_t> f_ct_ { 0 }; // commit flag
311
+ };
312
+
313
+ alignas(cache_line_size) std::atomic<circ::u2_t> ct_; // commit index
314
+ alignas(cache_line_size) std::atomic<rc_t> epoch_ { 0 };
315
+
316
+ circ::u2_t cursor() const noexcept {
317
+ return ct_.load(std::memory_order_acquire);
318
+ }
319
+
320
+ constexpr static rc_t inc_rc(rc_t rc) noexcept {
321
+ return (rc & ic_mask) | ((rc + ic_incr) & ~ic_mask);
322
+ }
323
+
324
+ constexpr static rc_t inc_mask(rc_t rc) noexcept {
325
+ return inc_rc(rc) & ~rc_mask;
326
+ }
327
+
328
+ template <typename W, typename F, typename E>
329
+ bool push(W* wrapper, F&& f, E* elems) {
330
+ E* el;
331
+ circ::u2_t cur_ct;
332
+ rc_t epoch = epoch_.load(std::memory_order_acquire);
333
+ for (unsigned k = 0;;) {
334
+ circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
335
+ if (cc == 0) return false; // no reader
336
+ el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
337
+ // check all consumers have finished reading this element
338
+ auto cur_rc = el->rc_.load(std::memory_order_relaxed);
339
+ circ::cc_t rem_cc = cur_rc & rc_mask;
340
+ if ((cc & rem_cc) && ((cur_rc & ~ep_mask) == epoch)) {
341
+ return false; // has not finished yet
342
+ }
343
+ else if (!rem_cc) {
344
+ auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
345
+ if ((cur_fl != cur_ct) && cur_fl) {
346
+ return false; // full
347
+ }
348
+ }
349
+ // consider rem_cc to be 0 here
350
+ if (el->rc_.compare_exchange_weak(
351
+ cur_rc, inc_mask(epoch | (cur_rc & ep_mask)) | static_cast<rc_t>(cc), std::memory_order_relaxed) &&
352
+ epoch_.compare_exchange_weak(epoch, epoch, std::memory_order_acq_rel)) {
353
+ break;
354
+ }
355
+ ipc::yield(k);
356
+ }
357
+ // only one thread/process would touch here at one time
358
+ ct_.store(cur_ct + 1, std::memory_order_release);
359
+ std::forward<F>(f)(&(el->data_));
360
+ // set flag & try update wt
361
+ el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
362
+ return true;
363
+ }
364
+
365
+ template <typename W, typename F, typename E>
366
+ bool force_push(W* wrapper, F&& f, E* elems) {
367
+ E* el;
368
+ circ::u2_t cur_ct;
369
+ rc_t epoch = epoch_.fetch_add(ep_incr, std::memory_order_release) + ep_incr;
370
+ for (unsigned k = 0;;) {
371
+ circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
372
+ if (cc == 0) return false; // no reader
373
+ el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
374
+ // check all consumers have finished reading this element
375
+ auto cur_rc = el->rc_.load(std::memory_order_acquire);
376
+ circ::cc_t rem_cc = cur_rc & rc_mask;
377
+ if (cc & rem_cc) {
378
+ ipc::log("force_push: k = %u, cc = %u, rem_cc = %u\n", k, cc, rem_cc);
379
+ cc = wrapper->elems()->disconnect_receiver(rem_cc); // disconnect all invalid readers
380
+ if (cc == 0) return false; // no reader
381
+ }
382
+ // just compare & exchange
383
+ if (el->rc_.compare_exchange_weak(
384
+ cur_rc, inc_mask(epoch | (cur_rc & ep_mask)) | static_cast<rc_t>(cc), std::memory_order_relaxed)) {
385
+ if (epoch == epoch_.load(std::memory_order_acquire)) {
386
+ break;
387
+ }
388
+ else if (push(wrapper, std::forward<F>(f), elems)) {
389
+ return true;
390
+ }
391
+ epoch = epoch_.fetch_add(ep_incr, std::memory_order_release) + ep_incr;
392
+ }
393
+ ipc::yield(k);
394
+ }
395
+ // only one thread/process would touch here at one time
396
+ ct_.store(cur_ct + 1, std::memory_order_release);
397
+ std::forward<F>(f)(&(el->data_));
398
+ // set flag & try update wt
399
+ el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
400
+ return true;
401
+ }
402
+
403
+ template <typename W, typename F, typename R, typename E, std::size_t N>
404
+ bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E(& elems)[N]) {
405
+ auto* el = elems + circ::index_of(cur);
406
+ auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
407
+ if (cur_fl != ~static_cast<flag_t>(cur)) {
408
+ return false; // empty
409
+ }
410
+ ++cur;
411
+ std::forward<F>(f)(&(el->data_));
412
+ for (unsigned k = 0;;) {
413
+ auto cur_rc = el->rc_.load(std::memory_order_acquire);
414
+ if ((cur_rc & rc_mask) == 0) {
415
+ std::forward<R>(out)(true);
416
+ el->f_ct_.store(cur + N - 1, std::memory_order_release);
417
+ return true;
418
+ }
419
+ auto nxt_rc = inc_rc(cur_rc) & ~static_cast<rc_t>(wrapper->connected_id());
420
+ bool last_one = false;
421
+ if ((last_one = (nxt_rc & rc_mask) == 0)) {
422
+ el->f_ct_.store(cur + N - 1, std::memory_order_release);
423
+ }
424
+ if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
425
+ std::forward<R>(out)(last_one);
426
+ return true;
427
+ }
428
+ ipc::yield(k);
429
+ }
430
+ }
431
+ };
432
+
433
+ } // namespace ipc
crazy_functions/test_project/cpp/cppipc/queue.h CHANGED
@@ -1,216 +1,216 @@
1
- #pragma once
2
-
3
- #include <type_traits>
4
- #include <new>
5
- #include <utility> // [[since C++14]]: std::exchange
6
- #include <algorithm>
7
- #include <atomic>
8
- #include <tuple>
9
- #include <thread>
10
- #include <chrono>
11
- #include <string>
12
- #include <cassert> // assert
13
-
14
- #include "libipc/def.h"
15
- #include "libipc/shm.h"
16
- #include "libipc/rw_lock.h"
17
-
18
- #include "libipc/utility/log.h"
19
- #include "libipc/platform/detail.h"
20
- #include "libipc/circ/elem_def.h"
21
-
22
- namespace ipc {
23
- namespace detail {
24
-
25
- class queue_conn {
26
- protected:
27
- circ::cc_t connected_ = 0;
28
- shm::handle elems_h_;
29
-
30
- template <typename Elems>
31
- Elems* open(char const * name) {
32
- if (name == nullptr || name[0] == '\0') {
33
- ipc::error("fail open waiter: name is empty!\n");
34
- return nullptr;
35
- }
36
- if (!elems_h_.acquire(name, sizeof(Elems))) {
37
- return nullptr;
38
- }
39
- auto elems = static_cast<Elems*>(elems_h_.get());
40
- if (elems == nullptr) {
41
- ipc::error("fail acquire elems: %s\n", name);
42
- return nullptr;
43
- }
44
- elems->init();
45
- return elems;
46
- }
47
-
48
- void close() {
49
- elems_h_.release();
50
- }
51
-
52
- public:
53
- queue_conn() = default;
54
- queue_conn(const queue_conn&) = delete;
55
- queue_conn& operator=(const queue_conn&) = delete;
56
-
57
- bool connected() const noexcept {
58
- return connected_ != 0;
59
- }
60
-
61
- circ::cc_t connected_id() const noexcept {
62
- return connected_;
63
- }
64
-
65
- template <typename Elems>
66
- auto connect(Elems* elems) noexcept
67
- /*needs 'optional' here*/
68
- -> std::tuple<bool, bool, decltype(std::declval<Elems>().cursor())> {
69
- if (elems == nullptr) return {};
70
- // if it's already connected, just return
71
- if (connected()) return {connected(), false, 0};
72
- connected_ = elems->connect_receiver();
73
- return {connected(), true, elems->cursor()};
74
- }
75
-
76
- template <typename Elems>
77
- bool disconnect(Elems* elems) noexcept {
78
- if (elems == nullptr) return false;
79
- // if it's already disconnected, just return false
80
- if (!connected()) return false;
81
- elems->disconnect_receiver(std::exchange(connected_, 0));
82
- return true;
83
- }
84
- };
85
-
86
- template <typename Elems>
87
- class queue_base : public queue_conn {
88
- using base_t = queue_conn;
89
-
90
- public:
91
- using elems_t = Elems;
92
- using policy_t = typename elems_t::policy_t;
93
-
94
- protected:
95
- elems_t * elems_ = nullptr;
96
- decltype(std::declval<elems_t>().cursor()) cursor_ = 0;
97
- bool sender_flag_ = false;
98
-
99
- public:
100
- using base_t::base_t;
101
-
102
- queue_base() = default;
103
-
104
- explicit queue_base(char const * name)
105
- : queue_base{} {
106
- elems_ = open<elems_t>(name);
107
- }
108
-
109
- explicit queue_base(elems_t * elems) noexcept
110
- : queue_base{} {
111
- assert(elems != nullptr);
112
- elems_ = elems;
113
- }
114
-
115
- /* not virtual */ ~queue_base() {
116
- base_t::close();
117
- }
118
-
119
- elems_t * elems() noexcept { return elems_; }
120
- elems_t const * elems() const noexcept { return elems_; }
121
-
122
- bool ready_sending() noexcept {
123
- if (elems_ == nullptr) return false;
124
- return sender_flag_ || (sender_flag_ = elems_->connect_sender());
125
- }
126
-
127
- void shut_sending() noexcept {
128
- if (elems_ == nullptr) return;
129
- if (!sender_flag_) return;
130
- elems_->disconnect_sender();
131
- }
132
-
133
- bool connect() noexcept {
134
- auto tp = base_t::connect(elems_);
135
- if (std::get<0>(tp) && std::get<1>(tp)) {
136
- cursor_ = std::get<2>(tp);
137
- return true;
138
- }
139
- return std::get<0>(tp);
140
- }
141
-
142
- bool disconnect() noexcept {
143
- return base_t::disconnect(elems_);
144
- }
145
-
146
- std::size_t conn_count() const noexcept {
147
- return (elems_ == nullptr) ? static_cast<std::size_t>(invalid_value) : elems_->conn_count();
148
- }
149
-
150
- bool valid() const noexcept {
151
- return elems_ != nullptr;
152
- }
153
-
154
- bool empty() const noexcept {
155
- return !valid() || (cursor_ == elems_->cursor());
156
- }
157
-
158
- template <typename T, typename F, typename... P>
159
- bool push(F&& prep, P&&... params) {
160
- if (elems_ == nullptr) return false;
161
- return elems_->push(this, [&](void* p) {
162
- if (prep(p)) ::new (p) T(std::forward<P>(params)...);
163
- });
164
- }
165
-
166
- template <typename T, typename F, typename... P>
167
- bool force_push(F&& prep, P&&... params) {
168
- if (elems_ == nullptr) return false;
169
- return elems_->force_push(this, [&](void* p) {
170
- if (prep(p)) ::new (p) T(std::forward<P>(params)...);
171
- });
172
- }
173
-
174
- template <typename T, typename F>
175
- bool pop(T& item, F&& out) {
176
- if (elems_ == nullptr) {
177
- return false;
178
- }
179
- return elems_->pop(this, &(this->cursor_), [&item](void* p) {
180
- ::new (&item) T(std::move(*static_cast<T*>(p)));
181
- }, std::forward<F>(out));
182
- }
183
- };
184
-
185
- } // namespace detail
186
-
187
- template <typename T, typename Policy>
188
- class queue final : public detail::queue_base<typename Policy::template elems_t<sizeof(T), alignof(T)>> {
189
- using base_t = detail::queue_base<typename Policy::template elems_t<sizeof(T), alignof(T)>>;
190
-
191
- public:
192
- using value_t = T;
193
-
194
- using base_t::base_t;
195
-
196
- template <typename... P>
197
- bool push(P&&... params) {
198
- return base_t::template push<T>(std::forward<P>(params)...);
199
- }
200
-
201
- template <typename... P>
202
- bool force_push(P&&... params) {
203
- return base_t::template force_push<T>(std::forward<P>(params)...);
204
- }
205
-
206
- bool pop(T& item) {
207
- return base_t::pop(item, [](bool) {});
208
- }
209
-
210
- template <typename F>
211
- bool pop(T& item, F&& out) {
212
- return base_t::pop(item, std::forward<F>(out));
213
- }
214
- };
215
-
216
- } // namespace ipc
 
1
+ #pragma once
2
+
3
+ #include <type_traits>
4
+ #include <new>
5
+ #include <utility> // [[since C++14]]: std::exchange
6
+ #include <algorithm>
7
+ #include <atomic>
8
+ #include <tuple>
9
+ #include <thread>
10
+ #include <chrono>
11
+ #include <string>
12
+ #include <cassert> // assert
13
+
14
+ #include "libipc/def.h"
15
+ #include "libipc/shm.h"
16
+ #include "libipc/rw_lock.h"
17
+
18
+ #include "libipc/utility/log.h"
19
+ #include "libipc/platform/detail.h"
20
+ #include "libipc/circ/elem_def.h"
21
+
22
+ namespace ipc {
23
+ namespace detail {
24
+
25
+ class queue_conn {
26
+ protected:
27
+ circ::cc_t connected_ = 0;
28
+ shm::handle elems_h_;
29
+
30
+ template <typename Elems>
31
+ Elems* open(char const * name) {
32
+ if (name == nullptr || name[0] == '\0') {
33
+ ipc::error("fail open waiter: name is empty!\n");
34
+ return nullptr;
35
+ }
36
+ if (!elems_h_.acquire(name, sizeof(Elems))) {
37
+ return nullptr;
38
+ }
39
+ auto elems = static_cast<Elems*>(elems_h_.get());
40
+ if (elems == nullptr) {
41
+ ipc::error("fail acquire elems: %s\n", name);
42
+ return nullptr;
43
+ }
44
+ elems->init();
45
+ return elems;
46
+ }
47
+
48
+ void close() {
49
+ elems_h_.release();
50
+ }
51
+
52
+ public:
53
+ queue_conn() = default;
54
+ queue_conn(const queue_conn&) = delete;
55
+ queue_conn& operator=(const queue_conn&) = delete;
56
+
57
+ bool connected() const noexcept {
58
+ return connected_ != 0;
59
+ }
60
+
61
+ circ::cc_t connected_id() const noexcept {
62
+ return connected_;
63
+ }
64
+
65
+ template <typename Elems>
66
+ auto connect(Elems* elems) noexcept
67
+ /*needs 'optional' here*/
68
+ -> std::tuple<bool, bool, decltype(std::declval<Elems>().cursor())> {
69
+ if (elems == nullptr) return {};
70
+ // if it's already connected, just return
71
+ if (connected()) return {connected(), false, 0};
72
+ connected_ = elems->connect_receiver();
73
+ return {connected(), true, elems->cursor()};
74
+ }
75
+
76
+ template <typename Elems>
77
+ bool disconnect(Elems* elems) noexcept {
78
+ if (elems == nullptr) return false;
79
+ // if it's already disconnected, just return false
80
+ if (!connected()) return false;
81
+ elems->disconnect_receiver(std::exchange(connected_, 0));
82
+ return true;
83
+ }
84
+ };
85
+
86
+ template <typename Elems>
87
+ class queue_base : public queue_conn {
88
+ using base_t = queue_conn;
89
+
90
+ public:
91
+ using elems_t = Elems;
92
+ using policy_t = typename elems_t::policy_t;
93
+
94
+ protected:
95
+ elems_t * elems_ = nullptr;
96
+ decltype(std::declval<elems_t>().cursor()) cursor_ = 0;
97
+ bool sender_flag_ = false;
98
+
99
+ public:
100
+ using base_t::base_t;
101
+
102
+ queue_base() = default;
103
+
104
+ explicit queue_base(char const * name)
105
+ : queue_base{} {
106
+ elems_ = open<elems_t>(name);
107
+ }
108
+
109
+ explicit queue_base(elems_t * elems) noexcept
110
+ : queue_base{} {
111
+ assert(elems != nullptr);
112
+ elems_ = elems;
113
+ }
114
+
115
+ /* not virtual */ ~queue_base() {
116
+ base_t::close();
117
+ }
118
+
119
+ elems_t * elems() noexcept { return elems_; }
120
+ elems_t const * elems() const noexcept { return elems_; }
121
+
122
+ bool ready_sending() noexcept {
123
+ if (elems_ == nullptr) return false;
124
+ return sender_flag_ || (sender_flag_ = elems_->connect_sender());
125
+ }
126
+
127
+ void shut_sending() noexcept {
128
+ if (elems_ == nullptr) return;
129
+ if (!sender_flag_) return;
130
+ elems_->disconnect_sender();
131
+ }
132
+
133
+ bool connect() noexcept {
134
+ auto tp = base_t::connect(elems_);
135
+ if (std::get<0>(tp) && std::get<1>(tp)) {
136
+ cursor_ = std::get<2>(tp);
137
+ return true;
138
+ }
139
+ return std::get<0>(tp);
140
+ }
141
+
142
+ bool disconnect() noexcept {
143
+ return base_t::disconnect(elems_);
144
+ }
145
+
146
+ std::size_t conn_count() const noexcept {
147
+ return (elems_ == nullptr) ? static_cast<std::size_t>(invalid_value) : elems_->conn_count();
148
+ }
149
+
150
+ bool valid() const noexcept {
151
+ return elems_ != nullptr;
152
+ }
153
+
154
+ bool empty() const noexcept {
155
+ return !valid() || (cursor_ == elems_->cursor());
156
+ }
157
+
158
+ template <typename T, typename F, typename... P>
159
+ bool push(F&& prep, P&&... params) {
160
+ if (elems_ == nullptr) return false;
161
+ return elems_->push(this, [&](void* p) {
162
+ if (prep(p)) ::new (p) T(std::forward<P>(params)...);
163
+ });
164
+ }
165
+
166
+ template <typename T, typename F, typename... P>
167
+ bool force_push(F&& prep, P&&... params) {
168
+ if (elems_ == nullptr) return false;
169
+ return elems_->force_push(this, [&](void* p) {
170
+ if (prep(p)) ::new (p) T(std::forward<P>(params)...);
171
+ });
172
+ }
173
+
174
+ template <typename T, typename F>
175
+ bool pop(T& item, F&& out) {
176
+ if (elems_ == nullptr) {
177
+ return false;
178
+ }
179
+ return elems_->pop(this, &(this->cursor_), [&item](void* p) {
180
+ ::new (&item) T(std::move(*static_cast<T*>(p)));
181
+ }, std::forward<F>(out));
182
+ }
183
+ };
184
+
185
+ } // namespace detail
186
+
187
+ template <typename T, typename Policy>
188
+ class queue final : public detail::queue_base<typename Policy::template elems_t<sizeof(T), alignof(T)>> {
189
+ using base_t = detail::queue_base<typename Policy::template elems_t<sizeof(T), alignof(T)>>;
190
+
191
+ public:
192
+ using value_t = T;
193
+
194
+ using base_t::base_t;
195
+
196
+ template <typename... P>
197
+ bool push(P&&... params) {
198
+ return base_t::template push<T>(std::forward<P>(params)...);
199
+ }
200
+
201
+ template <typename... P>
202
+ bool force_push(P&&... params) {
203
+ return base_t::template force_push<T>(std::forward<P>(params)...);
204
+ }
205
+
206
+ bool pop(T& item) {
207
+ return base_t::pop(item, [](bool) {});
208
+ }
209
+
210
+ template <typename F>
211
+ bool pop(T& item, F&& out) {
212
+ return base_t::pop(item, std::forward<F>(out));
213
+ }
214
+ };
215
+
216
+ } // namespace ipc
crazy_functions/test_project/cpp/cppipc/shm.cpp CHANGED
@@ -1,103 +1,103 @@
1
-
2
- #include <string>
3
- #include <utility>
4
-
5
- #include "libipc/shm.h"
6
-
7
- #include "libipc/utility/pimpl.h"
8
- #include "libipc/memory/resource.h"
9
-
10
- namespace ipc {
11
- namespace shm {
12
-
13
- class handle::handle_ : public pimpl<handle_> {
14
- public:
15
- shm::id_t id_ = nullptr;
16
- void* m_ = nullptr;
17
-
18
- ipc::string n_;
19
- std::size_t s_ = 0;
20
- };
21
-
22
- handle::handle()
23
- : p_(p_->make()) {
24
- }
25
-
26
- handle::handle(char const * name, std::size_t size, unsigned mode)
27
- : handle() {
28
- acquire(name, size, mode);
29
- }
30
-
31
- handle::handle(handle&& rhs)
32
- : handle() {
33
- swap(rhs);
34
- }
35
-
36
- handle::~handle() {
37
- release();
38
- p_->clear();
39
- }
40
-
41
- void handle::swap(handle& rhs) {
42
- std::swap(p_, rhs.p_);
43
- }
44
-
45
- handle& handle::operator=(handle rhs) {
46
- swap(rhs);
47
- return *this;
48
- }
49
-
50
- bool handle::valid() const noexcept {
51
- return impl(p_)->m_ != nullptr;
52
- }
53
-
54
- std::size_t handle::size() const noexcept {
55
- return impl(p_)->s_;
56
- }
57
-
58
- char const * handle::name() const noexcept {
59
- return impl(p_)->n_.c_str();
60
- }
61
-
62
- std::int32_t handle::ref() const noexcept {
63
- return shm::get_ref(impl(p_)->id_);
64
- }
65
-
66
- void handle::sub_ref() noexcept {
67
- shm::sub_ref(impl(p_)->id_);
68
- }
69
-
70
- bool handle::acquire(char const * name, std::size_t size, unsigned mode) {
71
- release();
72
- impl(p_)->id_ = shm::acquire((impl(p_)->n_ = name).c_str(), size, mode);
73
- impl(p_)->m_ = shm::get_mem(impl(p_)->id_, &(impl(p_)->s_));
74
- return valid();
75
- }
76
-
77
- std::int32_t handle::release() {
78
- if (impl(p_)->id_ == nullptr) return -1;
79
- return shm::release(detach());
80
- }
81
-
82
- void* handle::get() const {
83
- return impl(p_)->m_;
84
- }
85
-
86
- void handle::attach(id_t id) {
87
- if (id == nullptr) return;
88
- release();
89
- impl(p_)->id_ = id;
90
- impl(p_)->m_ = shm::get_mem(impl(p_)->id_, &(impl(p_)->s_));
91
- }
92
-
93
- id_t handle::detach() {
94
- auto old = impl(p_)->id_;
95
- impl(p_)->id_ = nullptr;
96
- impl(p_)->m_ = nullptr;
97
- impl(p_)->s_ = 0;
98
- impl(p_)->n_.clear();
99
- return old;
100
- }
101
-
102
- } // namespace shm
103
- } // namespace ipc
 
1
+
2
+ #include <string>
3
+ #include <utility>
4
+
5
+ #include "libipc/shm.h"
6
+
7
+ #include "libipc/utility/pimpl.h"
8
+ #include "libipc/memory/resource.h"
9
+
10
+ namespace ipc {
11
+ namespace shm {
12
+
13
+ class handle::handle_ : public pimpl<handle_> {
14
+ public:
15
+ shm::id_t id_ = nullptr;
16
+ void* m_ = nullptr;
17
+
18
+ ipc::string n_;
19
+ std::size_t s_ = 0;
20
+ };
21
+
22
+ handle::handle()
23
+ : p_(p_->make()) {
24
+ }
25
+
26
+ handle::handle(char const * name, std::size_t size, unsigned mode)
27
+ : handle() {
28
+ acquire(name, size, mode);
29
+ }
30
+
31
+ handle::handle(handle&& rhs)
32
+ : handle() {
33
+ swap(rhs);
34
+ }
35
+
36
+ handle::~handle() {
37
+ release();
38
+ p_->clear();
39
+ }
40
+
41
+ void handle::swap(handle& rhs) {
42
+ std::swap(p_, rhs.p_);
43
+ }
44
+
45
+ handle& handle::operator=(handle rhs) {
46
+ swap(rhs);
47
+ return *this;
48
+ }
49
+
50
+ bool handle::valid() const noexcept {
51
+ return impl(p_)->m_ != nullptr;
52
+ }
53
+
54
+ std::size_t handle::size() const noexcept {
55
+ return impl(p_)->s_;
56
+ }
57
+
58
+ char const * handle::name() const noexcept {
59
+ return impl(p_)->n_.c_str();
60
+ }
61
+
62
+ std::int32_t handle::ref() const noexcept {
63
+ return shm::get_ref(impl(p_)->id_);
64
+ }
65
+
66
+ void handle::sub_ref() noexcept {
67
+ shm::sub_ref(impl(p_)->id_);
68
+ }
69
+
70
+ bool handle::acquire(char const * name, std::size_t size, unsigned mode) {
71
+ release();
72
+ impl(p_)->id_ = shm::acquire((impl(p_)->n_ = name).c_str(), size, mode);
73
+ impl(p_)->m_ = shm::get_mem(impl(p_)->id_, &(impl(p_)->s_));
74
+ return valid();
75
+ }
76
+
77
+ std::int32_t handle::release() {
78
+ if (impl(p_)->id_ == nullptr) return -1;
79
+ return shm::release(detach());
80
+ }
81
+
82
+ void* handle::get() const {
83
+ return impl(p_)->m_;
84
+ }
85
+
86
+ void handle::attach(id_t id) {
87
+ if (id == nullptr) return;
88
+ release();
89
+ impl(p_)->id_ = id;
90
+ impl(p_)->m_ = shm::get_mem(impl(p_)->id_, &(impl(p_)->s_));
91
+ }
92
+
93
+ id_t handle::detach() {
94
+ auto old = impl(p_)->id_;
95
+ impl(p_)->id_ = nullptr;
96
+ impl(p_)->m_ = nullptr;
97
+ impl(p_)->s_ = 0;
98
+ impl(p_)->n_.clear();
99
+ return old;
100
+ }
101
+
102
+ } // namespace shm
103
+ } // namespace ipc
crazy_functions/test_project/cpp/longcode/prod_cons.h CHANGED
@@ -1,433 +1,433 @@
1
- #pragma once
2
-
3
- #include <atomic>
4
- #include <utility>
5
- #include <cstring>
6
- #include <type_traits>
7
- #include <cstdint>
8
-
9
- #include "libipc/def.h"
10
-
11
- #include "libipc/platform/detail.h"
12
- #include "libipc/circ/elem_def.h"
13
- #include "libipc/utility/log.h"
14
- #include "libipc/utility/utility.h"
15
-
16
- namespace ipc {
17
-
18
- ////////////////////////////////////////////////////////////////
19
- /// producer-consumer implementation
20
- ////////////////////////////////////////////////////////////////
21
-
22
- template <typename Flag>
23
- struct prod_cons_impl;
24
-
25
- template <>
26
- struct prod_cons_impl<wr<relat::single, relat::single, trans::unicast>> {
27
-
28
- template <std::size_t DataSize, std::size_t AlignSize>
29
- struct elem_t {
30
- std::aligned_storage_t<DataSize, AlignSize> data_ {};
31
- };
32
-
33
- alignas(cache_line_size) std::atomic<circ::u2_t> rd_; // read index
34
- alignas(cache_line_size) std::atomic<circ::u2_t> wt_; // write index
35
-
36
- constexpr circ::u2_t cursor() const noexcept {
37
- return 0;
38
- }
39
-
40
- template <typename W, typename F, typename E>
41
- bool push(W* /*wrapper*/, F&& f, E* elems) {
42
- auto cur_wt = circ::index_of(wt_.load(std::memory_order_relaxed));
43
- if (cur_wt == circ::index_of(rd_.load(std::memory_order_acquire) - 1)) {
44
- return false; // full
45
- }
46
- std::forward<F>(f)(&(elems[cur_wt].data_));
47
- wt_.fetch_add(1, std::memory_order_release);
48
- return true;
49
- }
50
-
51
- /**
52
- * In single-single-unicast, 'force_push' means 'no reader' or 'the only one reader is dead'.
53
- * So we could just disconnect all connections of receiver, and return false.
54
- */
55
- template <typename W, typename F, typename E>
56
- bool force_push(W* wrapper, F&&, E*) {
57
- wrapper->elems()->disconnect_receiver(~static_cast<circ::cc_t>(0u));
58
- return false;
59
- }
60
-
61
- template <typename W, typename F, typename R, typename E>
62
- bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E* elems) {
63
- auto cur_rd = circ::index_of(rd_.load(std::memory_order_relaxed));
64
- if (cur_rd == circ::index_of(wt_.load(std::memory_order_acquire))) {
65
- return false; // empty
66
- }
67
- std::forward<F>(f)(&(elems[cur_rd].data_));
68
- std::forward<R>(out)(true);
69
- rd_.fetch_add(1, std::memory_order_release);
70
- return true;
71
- }
72
- };
73
-
74
- template <>
75
- struct prod_cons_impl<wr<relat::single, relat::multi , trans::unicast>>
76
- : prod_cons_impl<wr<relat::single, relat::single, trans::unicast>> {
77
-
78
- template <typename W, typename F, typename E>
79
- bool force_push(W* wrapper, F&&, E*) {
80
- wrapper->elems()->disconnect_receiver(1);
81
- return false;
82
- }
83
-
84
- template <typename W, typename F, typename R,
85
- template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
86
- bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E<DS, AS>* elems) {
87
- byte_t buff[DS];
88
- for (unsigned k = 0;;) {
89
- auto cur_rd = rd_.load(std::memory_order_relaxed);
90
- if (circ::index_of(cur_rd) ==
91
- circ::index_of(wt_.load(std::memory_order_acquire))) {
92
- return false; // empty
93
- }
94
- std::memcpy(buff, &(elems[circ::index_of(cur_rd)].data_), sizeof(buff));
95
- if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
96
- std::forward<F>(f)(buff);
97
- std::forward<R>(out)(true);
98
- return true;
99
- }
100
- ipc::yield(k);
101
- }
102
- }
103
- };
104
-
105
- template <>
106
- struct prod_cons_impl<wr<relat::multi , relat::multi, trans::unicast>>
107
- : prod_cons_impl<wr<relat::single, relat::multi, trans::unicast>> {
108
-
109
- using flag_t = std::uint64_t;
110
-
111
- template <std::size_t DataSize, std::size_t AlignSize>
112
- struct elem_t {
113
- std::aligned_storage_t<DataSize, AlignSize> data_ {};
114
- std::atomic<flag_t> f_ct_ { 0 }; // commit flag
115
- };
116
-
117
- alignas(cache_line_size) std::atomic<circ::u2_t> ct_; // commit index
118
-
119
- template <typename W, typename F, typename E>
120
- bool push(W* /*wrapper*/, F&& f, E* elems) {
121
- circ::u2_t cur_ct, nxt_ct;
122
- for (unsigned k = 0;;) {
123
- cur_ct = ct_.load(std::memory_order_relaxed);
124
- if (circ::index_of(nxt_ct = cur_ct + 1) ==
125
- circ::index_of(rd_.load(std::memory_order_acquire))) {
126
- return false; // full
127
- }
128
- if (ct_.compare_exchange_weak(cur_ct, nxt_ct, std::memory_order_acq_rel)) {
129
- break;
130
- }
131
- ipc::yield(k);
132
- }
133
- auto* el = elems + circ::index_of(cur_ct);
134
- std::forward<F>(f)(&(el->data_));
135
- // set flag & try update wt
136
- el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
137
- while (1) {
138
- auto cac_ct = el->f_ct_.load(std::memory_order_acquire);
139
- if (cur_ct != wt_.load(std::memory_order_relaxed)) {
140
- return true;
141
- }
142
- if ((~cac_ct) != cur_ct) {
143
- return true;
144
- }
145
- if (!el->f_ct_.compare_exchange_strong(cac_ct, 0, std::memory_order_relaxed)) {
146
- return true;
147
- }
148
- wt_.store(nxt_ct, std::memory_order_release);
149
- cur_ct = nxt_ct;
150
- nxt_ct = cur_ct + 1;
151
- el = elems + circ::index_of(cur_ct);
152
- }
153
- return true;
154
- }
155
-
156
- template <typename W, typename F, typename E>
157
- bool force_push(W* wrapper, F&&, E*) {
158
- wrapper->elems()->disconnect_receiver(1);
159
- return false;
160
- }
161
-
162
- template <typename W, typename F, typename R,
163
- template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
164
- bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E<DS, AS>* elems) {
165
- byte_t buff[DS];
166
- for (unsigned k = 0;;) {
167
- auto cur_rd = rd_.load(std::memory_order_relaxed);
168
- auto cur_wt = wt_.load(std::memory_order_acquire);
169
- auto id_rd = circ::index_of(cur_rd);
170
- auto id_wt = circ::index_of(cur_wt);
171
- if (id_rd == id_wt) {
172
- auto* el = elems + id_wt;
173
- auto cac_ct = el->f_ct_.load(std::memory_order_acquire);
174
- if ((~cac_ct) != cur_wt) {
175
- return false; // empty
176
- }
177
- if (el->f_ct_.compare_exchange_weak(cac_ct, 0, std::memory_order_relaxed)) {
178
- wt_.store(cur_wt + 1, std::memory_order_release);
179
- }
180
- k = 0;
181
- }
182
- else {
183
- std::memcpy(buff, &(elems[circ::index_of(cur_rd)].data_), sizeof(buff));
184
- if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
185
- std::forward<F>(f)(buff);
186
- std::forward<R>(out)(true);
187
- return true;
188
- }
189
- ipc::yield(k);
190
- }
191
- }
192
- }
193
- };
194
-
195
- template <>
196
- struct prod_cons_impl<wr<relat::single, relat::multi, trans::broadcast>> {
197
-
198
- using rc_t = std::uint64_t;
199
-
200
- enum : rc_t {
201
- ep_mask = 0x00000000ffffffffull,
202
- ep_incr = 0x0000000100000000ull
203
- };
204
-
205
- template <std::size_t DataSize, std::size_t AlignSize>
206
- struct elem_t {
207
- std::aligned_storage_t<DataSize, AlignSize> data_ {};
208
- std::atomic<rc_t> rc_ { 0 }; // read-counter
209
- };
210
-
211
- alignas(cache_line_size) std::atomic<circ::u2_t> wt_; // write index
212
- alignas(cache_line_size) rc_t epoch_ { 0 }; // only one writer
213
-
214
- circ::u2_t cursor() const noexcept {
215
- return wt_.load(std::memory_order_acquire);
216
- }
217
-
218
- template <typename W, typename F, typename E>
219
- bool push(W* wrapper, F&& f, E* elems) {
220
- E* el;
221
- for (unsigned k = 0;;) {
222
- circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
223
- if (cc == 0) return false; // no reader
224
- el = elems + circ::index_of(wt_.load(std::memory_order_relaxed));
225
- // check all consumers have finished reading this element
226
- auto cur_rc = el->rc_.load(std::memory_order_acquire);
227
- circ::cc_t rem_cc = cur_rc & ep_mask;
228
- if ((cc & rem_cc) && ((cur_rc & ~ep_mask) == epoch_)) {
229
- return false; // has not finished yet
230
- }
231
- // consider rem_cc to be 0 here
232
- if (el->rc_.compare_exchange_weak(
233
- cur_rc, epoch_ | static_cast<rc_t>(cc), std::memory_order_release)) {
234
- break;
235
- }
236
- ipc::yield(k);
237
- }
238
- std::forward<F>(f)(&(el->data_));
239
- wt_.fetch_add(1, std::memory_order_release);
240
- return true;
241
- }
242
-
243
- template <typename W, typename F, typename E>
244
- bool force_push(W* wrapper, F&& f, E* elems) {
245
- E* el;
246
- epoch_ += ep_incr;
247
- for (unsigned k = 0;;) {
248
- circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
249
- if (cc == 0) return false; // no reader
250
- el = elems + circ::index_of(wt_.load(std::memory_order_relaxed));
251
- // check all consumers have finished reading this element
252
- auto cur_rc = el->rc_.load(std::memory_order_acquire);
253
- circ::cc_t rem_cc = cur_rc & ep_mask;
254
- if (cc & rem_cc) {
255
- ipc::log("force_push: k = %u, cc = %u, rem_cc = %u\n", k, cc, rem_cc);
256
- cc = wrapper->elems()->disconnect_receiver(rem_cc); // disconnect all invalid readers
257
- if (cc == 0) return false; // no reader
258
- }
259
- // just compare & exchange
260
- if (el->rc_.compare_exchange_weak(
261
- cur_rc, epoch_ | static_cast<rc_t>(cc), std::memory_order_release)) {
262
- break;
263
- }
264
- ipc::yield(k);
265
- }
266
- std::forward<F>(f)(&(el->data_));
267
- wt_.fetch_add(1, std::memory_order_release);
268
- return true;
269
- }
270
-
271
- template <typename W, typename F, typename R, typename E>
272
- bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E* elems) {
273
- if (cur == cursor()) return false; // acquire
274
- auto* el = elems + circ::index_of(cur++);
275
- std::forward<F>(f)(&(el->data_));
276
- for (unsigned k = 0;;) {
277
- auto cur_rc = el->rc_.load(std::memory_order_acquire);
278
- if ((cur_rc & ep_mask) == 0) {
279
- std::forward<R>(out)(true);
280
- return true;
281
- }
282
- auto nxt_rc = cur_rc & ~static_cast<rc_t>(wrapper->connected_id());
283
- if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
284
- std::forward<R>(out)((nxt_rc & ep_mask) == 0);
285
- return true;
286
- }
287
- ipc::yield(k);
288
- }
289
- }
290
- };
291
-
292
- template <>
293
- struct prod_cons_impl<wr<relat::multi, relat::multi, trans::broadcast>> {
294
-
295
- using rc_t = std::uint64_t;
296
- using flag_t = std::uint64_t;
297
-
298
- enum : rc_t {
299
- rc_mask = 0x00000000ffffffffull,
300
- ep_mask = 0x00ffffffffffffffull,
301
- ep_incr = 0x0100000000000000ull,
302
- ic_mask = 0xff000000ffffffffull,
303
- ic_incr = 0x0000000100000000ull
304
- };
305
-
306
- template <std::size_t DataSize, std::size_t AlignSize>
307
- struct elem_t {
308
- std::aligned_storage_t<DataSize, AlignSize> data_ {};
309
- std::atomic<rc_t > rc_ { 0 }; // read-counter
310
- std::atomic<flag_t> f_ct_ { 0 }; // commit flag
311
- };
312
-
313
- alignas(cache_line_size) std::atomic<circ::u2_t> ct_; // commit index
314
- alignas(cache_line_size) std::atomic<rc_t> epoch_ { 0 };
315
-
316
- circ::u2_t cursor() const noexcept {
317
- return ct_.load(std::memory_order_acquire);
318
- }
319
-
320
- constexpr static rc_t inc_rc(rc_t rc) noexcept {
321
- return (rc & ic_mask) | ((rc + ic_incr) & ~ic_mask);
322
- }
323
-
324
- constexpr static rc_t inc_mask(rc_t rc) noexcept {
325
- return inc_rc(rc) & ~rc_mask;
326
- }
327
-
328
- template <typename W, typename F, typename E>
329
- bool push(W* wrapper, F&& f, E* elems) {
330
- E* el;
331
- circ::u2_t cur_ct;
332
- rc_t epoch = epoch_.load(std::memory_order_acquire);
333
- for (unsigned k = 0;;) {
334
- circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
335
- if (cc == 0) return false; // no reader
336
- el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
337
- // check all consumers have finished reading this element
338
- auto cur_rc = el->rc_.load(std::memory_order_relaxed);
339
- circ::cc_t rem_cc = cur_rc & rc_mask;
340
- if ((cc & rem_cc) && ((cur_rc & ~ep_mask) == epoch)) {
341
- return false; // has not finished yet
342
- }
343
- else if (!rem_cc) {
344
- auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
345
- if ((cur_fl != cur_ct) && cur_fl) {
346
- return false; // full
347
- }
348
- }
349
- // consider rem_cc to be 0 here
350
- if (el->rc_.compare_exchange_weak(
351
- cur_rc, inc_mask(epoch | (cur_rc & ep_mask)) | static_cast<rc_t>(cc), std::memory_order_relaxed) &&
352
- epoch_.compare_exchange_weak(epoch, epoch, std::memory_order_acq_rel)) {
353
- break;
354
- }
355
- ipc::yield(k);
356
- }
357
- // only one thread/process would touch here at one time
358
- ct_.store(cur_ct + 1, std::memory_order_release);
359
- std::forward<F>(f)(&(el->data_));
360
- // set flag & try update wt
361
- el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
362
- return true;
363
- }
364
-
365
- template <typename W, typename F, typename E>
366
- bool force_push(W* wrapper, F&& f, E* elems) {
367
- E* el;
368
- circ::u2_t cur_ct;
369
- rc_t epoch = epoch_.fetch_add(ep_incr, std::memory_order_release) + ep_incr;
370
- for (unsigned k = 0;;) {
371
- circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
372
- if (cc == 0) return false; // no reader
373
- el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
374
- // check all consumers have finished reading this element
375
- auto cur_rc = el->rc_.load(std::memory_order_acquire);
376
- circ::cc_t rem_cc = cur_rc & rc_mask;
377
- if (cc & rem_cc) {
378
- ipc::log("force_push: k = %u, cc = %u, rem_cc = %u\n", k, cc, rem_cc);
379
- cc = wrapper->elems()->disconnect_receiver(rem_cc); // disconnect all invalid readers
380
- if (cc == 0) return false; // no reader
381
- }
382
- // just compare & exchange
383
- if (el->rc_.compare_exchange_weak(
384
- cur_rc, inc_mask(epoch | (cur_rc & ep_mask)) | static_cast<rc_t>(cc), std::memory_order_relaxed)) {
385
- if (epoch == epoch_.load(std::memory_order_acquire)) {
386
- break;
387
- }
388
- else if (push(wrapper, std::forward<F>(f), elems)) {
389
- return true;
390
- }
391
- epoch = epoch_.fetch_add(ep_incr, std::memory_order_release) + ep_incr;
392
- }
393
- ipc::yield(k);
394
- }
395
- // only one thread/process would touch here at one time
396
- ct_.store(cur_ct + 1, std::memory_order_release);
397
- std::forward<F>(f)(&(el->data_));
398
- // set flag & try update wt
399
- el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
400
- return true;
401
- }
402
-
403
- template <typename W, typename F, typename R, typename E, std::size_t N>
404
- bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E(& elems)[N]) {
405
- auto* el = elems + circ::index_of(cur);
406
- auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
407
- if (cur_fl != ~static_cast<flag_t>(cur)) {
408
- return false; // empty
409
- }
410
- ++cur;
411
- std::forward<F>(f)(&(el->data_));
412
- for (unsigned k = 0;;) {
413
- auto cur_rc = el->rc_.load(std::memory_order_acquire);
414
- if ((cur_rc & rc_mask) == 0) {
415
- std::forward<R>(out)(true);
416
- el->f_ct_.store(cur + N - 1, std::memory_order_release);
417
- return true;
418
- }
419
- auto nxt_rc = inc_rc(cur_rc) & ~static_cast<rc_t>(wrapper->connected_id());
420
- bool last_one = false;
421
- if ((last_one = (nxt_rc & rc_mask) == 0)) {
422
- el->f_ct_.store(cur + N - 1, std::memory_order_release);
423
- }
424
- if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
425
- std::forward<R>(out)(last_one);
426
- return true;
427
- }
428
- ipc::yield(k);
429
- }
430
- }
431
- };
432
-
433
- } // namespace ipc
 
1
+ #pragma once
2
+
3
+ #include <atomic>
4
+ #include <utility>
5
+ #include <cstring>
6
+ #include <type_traits>
7
+ #include <cstdint>
8
+
9
+ #include "libipc/def.h"
10
+
11
+ #include "libipc/platform/detail.h"
12
+ #include "libipc/circ/elem_def.h"
13
+ #include "libipc/utility/log.h"
14
+ #include "libipc/utility/utility.h"
15
+
16
+ namespace ipc {
17
+
18
+ ////////////////////////////////////////////////////////////////
19
+ /// producer-consumer implementation
20
+ ////////////////////////////////////////////////////////////////
21
+
22
+ template <typename Flag>
23
+ struct prod_cons_impl;
24
+
25
+ template <>
26
+ struct prod_cons_impl<wr<relat::single, relat::single, trans::unicast>> {
27
+
28
+ template <std::size_t DataSize, std::size_t AlignSize>
29
+ struct elem_t {
30
+ std::aligned_storage_t<DataSize, AlignSize> data_ {};
31
+ };
32
+
33
+ alignas(cache_line_size) std::atomic<circ::u2_t> rd_; // read index
34
+ alignas(cache_line_size) std::atomic<circ::u2_t> wt_; // write index
35
+
36
+ constexpr circ::u2_t cursor() const noexcept {
37
+ return 0;
38
+ }
39
+
40
+ template <typename W, typename F, typename E>
41
+ bool push(W* /*wrapper*/, F&& f, E* elems) {
42
+ auto cur_wt = circ::index_of(wt_.load(std::memory_order_relaxed));
43
+ if (cur_wt == circ::index_of(rd_.load(std::memory_order_acquire) - 1)) {
44
+ return false; // full
45
+ }
46
+ std::forward<F>(f)(&(elems[cur_wt].data_));
47
+ wt_.fetch_add(1, std::memory_order_release);
48
+ return true;
49
+ }
50
+
51
+ /**
52
+ * In single-single-unicast, 'force_push' means 'no reader' or 'the only one reader is dead'.
53
+ * So we could just disconnect all connections of receiver, and return false.
54
+ */
55
+ template <typename W, typename F, typename E>
56
+ bool force_push(W* wrapper, F&&, E*) {
57
+ wrapper->elems()->disconnect_receiver(~static_cast<circ::cc_t>(0u));
58
+ return false;
59
+ }
60
+
61
+ template <typename W, typename F, typename R, typename E>
62
+ bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E* elems) {
63
+ auto cur_rd = circ::index_of(rd_.load(std::memory_order_relaxed));
64
+ if (cur_rd == circ::index_of(wt_.load(std::memory_order_acquire))) {
65
+ return false; // empty
66
+ }
67
+ std::forward<F>(f)(&(elems[cur_rd].data_));
68
+ std::forward<R>(out)(true);
69
+ rd_.fetch_add(1, std::memory_order_release);
70
+ return true;
71
+ }
72
+ };
73
+
74
+ template <>
75
+ struct prod_cons_impl<wr<relat::single, relat::multi , trans::unicast>>
76
+ : prod_cons_impl<wr<relat::single, relat::single, trans::unicast>> {
77
+
78
+ template <typename W, typename F, typename E>
79
+ bool force_push(W* wrapper, F&&, E*) {
80
+ wrapper->elems()->disconnect_receiver(1);
81
+ return false;
82
+ }
83
+
84
+ template <typename W, typename F, typename R,
85
+ template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
86
+ bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E<DS, AS>* elems) {
87
+ byte_t buff[DS];
88
+ for (unsigned k = 0;;) {
89
+ auto cur_rd = rd_.load(std::memory_order_relaxed);
90
+ if (circ::index_of(cur_rd) ==
91
+ circ::index_of(wt_.load(std::memory_order_acquire))) {
92
+ return false; // empty
93
+ }
94
+ std::memcpy(buff, &(elems[circ::index_of(cur_rd)].data_), sizeof(buff));
95
+ if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
96
+ std::forward<F>(f)(buff);
97
+ std::forward<R>(out)(true);
98
+ return true;
99
+ }
100
+ ipc::yield(k);
101
+ }
102
+ }
103
+ };
104
+
105
+ template <>
106
+ struct prod_cons_impl<wr<relat::multi , relat::multi, trans::unicast>>
107
+ : prod_cons_impl<wr<relat::single, relat::multi, trans::unicast>> {
108
+
109
+ using flag_t = std::uint64_t;
110
+
111
+ template <std::size_t DataSize, std::size_t AlignSize>
112
+ struct elem_t {
113
+ std::aligned_storage_t<DataSize, AlignSize> data_ {};
114
+ std::atomic<flag_t> f_ct_ { 0 }; // commit flag
115
+ };
116
+
117
+ alignas(cache_line_size) std::atomic<circ::u2_t> ct_; // commit index
118
+
119
+ template <typename W, typename F, typename E>
120
+ bool push(W* /*wrapper*/, F&& f, E* elems) {
121
+ circ::u2_t cur_ct, nxt_ct;
122
+ for (unsigned k = 0;;) {
123
+ cur_ct = ct_.load(std::memory_order_relaxed);
124
+ if (circ::index_of(nxt_ct = cur_ct + 1) ==
125
+ circ::index_of(rd_.load(std::memory_order_acquire))) {
126
+ return false; // full
127
+ }
128
+ if (ct_.compare_exchange_weak(cur_ct, nxt_ct, std::memory_order_acq_rel)) {
129
+ break;
130
+ }
131
+ ipc::yield(k);
132
+ }
133
+ auto* el = elems + circ::index_of(cur_ct);
134
+ std::forward<F>(f)(&(el->data_));
135
+ // set flag & try update wt
136
+ el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
137
+ while (1) {
138
+ auto cac_ct = el->f_ct_.load(std::memory_order_acquire);
139
+ if (cur_ct != wt_.load(std::memory_order_relaxed)) {
140
+ return true;
141
+ }
142
+ if ((~cac_ct) != cur_ct) {
143
+ return true;
144
+ }
145
+ if (!el->f_ct_.compare_exchange_strong(cac_ct, 0, std::memory_order_relaxed)) {
146
+ return true;
147
+ }
148
+ wt_.store(nxt_ct, std::memory_order_release);
149
+ cur_ct = nxt_ct;
150
+ nxt_ct = cur_ct + 1;
151
+ el = elems + circ::index_of(cur_ct);
152
+ }
153
+ return true;
154
+ }
155
+
156
+ template <typename W, typename F, typename E>
157
+ bool force_push(W* wrapper, F&&, E*) {
158
+ wrapper->elems()->disconnect_receiver(1);
159
+ return false;
160
+ }
161
+
162
+ template <typename W, typename F, typename R,
163
+ template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
164
+ bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E<DS, AS>* elems) {
165
+ byte_t buff[DS];
166
+ for (unsigned k = 0;;) {
167
+ auto cur_rd = rd_.load(std::memory_order_relaxed);
168
+ auto cur_wt = wt_.load(std::memory_order_acquire);
169
+ auto id_rd = circ::index_of(cur_rd);
170
+ auto id_wt = circ::index_of(cur_wt);
171
+ if (id_rd == id_wt) {
172
+ auto* el = elems + id_wt;
173
+ auto cac_ct = el->f_ct_.load(std::memory_order_acquire);
174
+ if ((~cac_ct) != cur_wt) {
175
+ return false; // empty
176
+ }
177
+ if (el->f_ct_.compare_exchange_weak(cac_ct, 0, std::memory_order_relaxed)) {
178
+ wt_.store(cur_wt + 1, std::memory_order_release);
179
+ }
180
+ k = 0;
181
+ }
182
+ else {
183
+ std::memcpy(buff, &(elems[circ::index_of(cur_rd)].data_), sizeof(buff));
184
+ if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
185
+ std::forward<F>(f)(buff);
186
+ std::forward<R>(out)(true);
187
+ return true;
188
+ }
189
+ ipc::yield(k);
190
+ }
191
+ }
192
+ }
193
+ };
194
+
195
+ template <>
196
+ struct prod_cons_impl<wr<relat::single, relat::multi, trans::broadcast>> {
197
+
198
+ using rc_t = std::uint64_t;
199
+
200
+ enum : rc_t {
201
+ ep_mask = 0x00000000ffffffffull,
202
+ ep_incr = 0x0000000100000000ull
203
+ };
204
+
205
+ template <std::size_t DataSize, std::size_t AlignSize>
206
+ struct elem_t {
207
+ std::aligned_storage_t<DataSize, AlignSize> data_ {};
208
+ std::atomic<rc_t> rc_ { 0 }; // read-counter
209
+ };
210
+
211
+ alignas(cache_line_size) std::atomic<circ::u2_t> wt_; // write index
212
+ alignas(cache_line_size) rc_t epoch_ { 0 }; // only one writer
213
+
214
+ circ::u2_t cursor() const noexcept {
215
+ return wt_.load(std::memory_order_acquire);
216
+ }
217
+
218
+ template <typename W, typename F, typename E>
219
+ bool push(W* wrapper, F&& f, E* elems) {
220
+ E* el;
221
+ for (unsigned k = 0;;) {
222
+ circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
223
+ if (cc == 0) return false; // no reader
224
+ el = elems + circ::index_of(wt_.load(std::memory_order_relaxed));
225
+ // check all consumers have finished reading this element
226
+ auto cur_rc = el->rc_.load(std::memory_order_acquire);
227
+ circ::cc_t rem_cc = cur_rc & ep_mask;
228
+ if ((cc & rem_cc) && ((cur_rc & ~ep_mask) == epoch_)) {
229
+ return false; // has not finished yet
230
+ }
231
+ // consider rem_cc to be 0 here
232
+ if (el->rc_.compare_exchange_weak(
233
+ cur_rc, epoch_ | static_cast<rc_t>(cc), std::memory_order_release)) {
234
+ break;
235
+ }
236
+ ipc::yield(k);
237
+ }
238
+ std::forward<F>(f)(&(el->data_));
239
+ wt_.fetch_add(1, std::memory_order_release);
240
+ return true;
241
+ }
242
+
243
+ template <typename W, typename F, typename E>
244
+ bool force_push(W* wrapper, F&& f, E* elems) {
245
+ E* el;
246
+ epoch_ += ep_incr;
247
+ for (unsigned k = 0;;) {
248
+ circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
249
+ if (cc == 0) return false; // no reader
250
+ el = elems + circ::index_of(wt_.load(std::memory_order_relaxed));
251
+ // check all consumers have finished reading this element
252
+ auto cur_rc = el->rc_.load(std::memory_order_acquire);
253
+ circ::cc_t rem_cc = cur_rc & ep_mask;
254
+ if (cc & rem_cc) {
255
+ ipc::log("force_push: k = %u, cc = %u, rem_cc = %u\n", k, cc, rem_cc);
256
+ cc = wrapper->elems()->disconnect_receiver(rem_cc); // disconnect all invalid readers
257
+ if (cc == 0) return false; // no reader
258
+ }
259
+ // just compare & exchange
260
+ if (el->rc_.compare_exchange_weak(
261
+ cur_rc, epoch_ | static_cast<rc_t>(cc), std::memory_order_release)) {
262
+ break;
263
+ }
264
+ ipc::yield(k);
265
+ }
266
+ std::forward<F>(f)(&(el->data_));
267
+ wt_.fetch_add(1, std::memory_order_release);
268
+ return true;
269
+ }
270
+
271
+ template <typename W, typename F, typename R, typename E>
272
+ bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E* elems) {
273
+ if (cur == cursor()) return false; // acquire
274
+ auto* el = elems + circ::index_of(cur++);
275
+ std::forward<F>(f)(&(el->data_));
276
+ for (unsigned k = 0;;) {
277
+ auto cur_rc = el->rc_.load(std::memory_order_acquire);
278
+ if ((cur_rc & ep_mask) == 0) {
279
+ std::forward<R>(out)(true);
280
+ return true;
281
+ }
282
+ auto nxt_rc = cur_rc & ~static_cast<rc_t>(wrapper->connected_id());
283
+ if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
284
+ std::forward<R>(out)((nxt_rc & ep_mask) == 0);
285
+ return true;
286
+ }
287
+ ipc::yield(k);
288
+ }
289
+ }
290
+ };
291
+
292
+ template <>
293
+ struct prod_cons_impl<wr<relat::multi, relat::multi, trans::broadcast>> {
294
+
295
+ using rc_t = std::uint64_t;
296
+ using flag_t = std::uint64_t;
297
+
298
+ enum : rc_t {
299
+ rc_mask = 0x00000000ffffffffull,
300
+ ep_mask = 0x00ffffffffffffffull,
301
+ ep_incr = 0x0100000000000000ull,
302
+ ic_mask = 0xff000000ffffffffull,
303
+ ic_incr = 0x0000000100000000ull
304
+ };
305
+
306
+ template <std::size_t DataSize, std::size_t AlignSize>
307
+ struct elem_t {
308
+ std::aligned_storage_t<DataSize, AlignSize> data_ {};
309
+ std::atomic<rc_t > rc_ { 0 }; // read-counter
310
+ std::atomic<flag_t> f_ct_ { 0 }; // commit flag
311
+ };
312
+
313
+ alignas(cache_line_size) std::atomic<circ::u2_t> ct_; // commit index
314
+ alignas(cache_line_size) std::atomic<rc_t> epoch_ { 0 };
315
+
316
+ circ::u2_t cursor() const noexcept {
317
+ return ct_.load(std::memory_order_acquire);
318
+ }
319
+
320
+ constexpr static rc_t inc_rc(rc_t rc) noexcept {
321
+ return (rc & ic_mask) | ((rc + ic_incr) & ~ic_mask);
322
+ }
323
+
324
+ constexpr static rc_t inc_mask(rc_t rc) noexcept {
325
+ return inc_rc(rc) & ~rc_mask;
326
+ }
327
+
328
+ template <typename W, typename F, typename E>
329
+ bool push(W* wrapper, F&& f, E* elems) {
330
+ E* el;
331
+ circ::u2_t cur_ct;
332
+ rc_t epoch = epoch_.load(std::memory_order_acquire);
333
+ for (unsigned k = 0;;) {
334
+ circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
335
+ if (cc == 0) return false; // no reader
336
+ el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
337
+ // check all consumers have finished reading this element
338
+ auto cur_rc = el->rc_.load(std::memory_order_relaxed);
339
+ circ::cc_t rem_cc = cur_rc & rc_mask;
340
+ if ((cc & rem_cc) && ((cur_rc & ~ep_mask) == epoch)) {
341
+ return false; // has not finished yet
342
+ }
343
+ else if (!rem_cc) {
344
+ auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
345
+ if ((cur_fl != cur_ct) && cur_fl) {
346
+ return false; // full
347
+ }
348
+ }
349
+ // consider rem_cc to be 0 here
350
+ if (el->rc_.compare_exchange_weak(
351
+ cur_rc, inc_mask(epoch | (cur_rc & ep_mask)) | static_cast<rc_t>(cc), std::memory_order_relaxed) &&
352
+ epoch_.compare_exchange_weak(epoch, epoch, std::memory_order_acq_rel)) {
353
+ break;
354
+ }
355
+ ipc::yield(k);
356
+ }
357
+ // only one thread/process would touch here at one time
358
+ ct_.store(cur_ct + 1, std::memory_order_release);
359
+ std::forward<F>(f)(&(el->data_));
360
+ // set flag & try update wt
361
+ el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
362
+ return true;
363
+ }
364
+
365
+ template <typename W, typename F, typename E>
366
+ bool force_push(W* wrapper, F&& f, E* elems) {
367
+ E* el;
368
+ circ::u2_t cur_ct;
369
+ rc_t epoch = epoch_.fetch_add(ep_incr, std::memory_order_release) + ep_incr;
370
+ for (unsigned k = 0;;) {
371
+ circ::cc_t cc = wrapper->elems()->connections(std::memory_order_relaxed);
372
+ if (cc == 0) return false; // no reader
373
+ el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
374
+ // check all consumers have finished reading this element
375
+ auto cur_rc = el->rc_.load(std::memory_order_acquire);
376
+ circ::cc_t rem_cc = cur_rc & rc_mask;
377
+ if (cc & rem_cc) {
378
+ ipc::log("force_push: k = %u, cc = %u, rem_cc = %u\n", k, cc, rem_cc);
379
+ cc = wrapper->elems()->disconnect_receiver(rem_cc); // disconnect all invalid readers
380
+ if (cc == 0) return false; // no reader
381
+ }
382
+ // just compare & exchange
383
+ if (el->rc_.compare_exchange_weak(
384
+ cur_rc, inc_mask(epoch | (cur_rc & ep_mask)) | static_cast<rc_t>(cc), std::memory_order_relaxed)) {
385
+ if (epoch == epoch_.load(std::memory_order_acquire)) {
386
+ break;
387
+ }
388
+ else if (push(wrapper, std::forward<F>(f), elems)) {
389
+ return true;
390
+ }
391
+ epoch = epoch_.fetch_add(ep_incr, std::memory_order_release) + ep_incr;
392
+ }
393
+ ipc::yield(k);
394
+ }
395
+ // only one thread/process would touch here at one time
396
+ ct_.store(cur_ct + 1, std::memory_order_release);
397
+ std::forward<F>(f)(&(el->data_));
398
+ // set flag & try update wt
399
+ el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
400
+ return true;
401
+ }
402
+
403
+ template <typename W, typename F, typename R, typename E, std::size_t N>
404
+ bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E(& elems)[N]) {
405
+ auto* el = elems + circ::index_of(cur);
406
+ auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
407
+ if (cur_fl != ~static_cast<flag_t>(cur)) {
408
+ return false; // empty
409
+ }
410
+ ++cur;
411
+ std::forward<F>(f)(&(el->data_));
412
+ for (unsigned k = 0;;) {
413
+ auto cur_rc = el->rc_.load(std::memory_order_acquire);
414
+ if ((cur_rc & rc_mask) == 0) {
415
+ std::forward<R>(out)(true);
416
+ el->f_ct_.store(cur + N - 1, std::memory_order_release);
417
+ return true;
418
+ }
419
+ auto nxt_rc = inc_rc(cur_rc) & ~static_cast<rc_t>(wrapper->connected_id());
420
+ bool last_one = false;
421
+ if ((last_one = (nxt_rc & rc_mask) == 0)) {
422
+ el->f_ct_.store(cur + N - 1, std::memory_order_release);
423
+ }
424
+ if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
425
+ std::forward<R>(out)(last_one);
426
+ return true;
427
+ }
428
+ ipc::yield(k);
429
+ }
430
+ }
431
+ };
432
+
433
+ } // namespace ipc
request_llm/bridge_all.py CHANGED
@@ -157,7 +157,7 @@ model_info = {
157
  "fn_with_ui": chatglm_ui,
158
  "fn_without_ui": chatglm_noui,
159
  "endpoint": None,
160
- "max_token": 1024,
161
  "tokenizer": tokenizer_gpt35,
162
  "token_cnt": get_token_num_gpt35,
163
  },
@@ -165,7 +165,7 @@ model_info = {
165
  "fn_with_ui": chatglm_ui,
166
  "fn_without_ui": chatglm_noui,
167
  "endpoint": None,
168
- "max_token": 1024,
169
  "tokenizer": tokenizer_gpt35,
170
  "token_cnt": get_token_num_gpt35,
171
  },
 
157
  "fn_with_ui": chatglm_ui,
158
  "fn_without_ui": chatglm_noui,
159
  "endpoint": None,
160
+ "max_token": 40960,
161
  "tokenizer": tokenizer_gpt35,
162
  "token_cnt": get_token_num_gpt35,
163
  },
 
165
  "fn_with_ui": chatglm_ui,
166
  "fn_without_ui": chatglm_noui,
167
  "endpoint": None,
168
+ "max_token": 40960,
169
  "tokenizer": tokenizer_gpt35,
170
  "token_cnt": get_token_num_gpt35,
171
  },
request_llm/bridge_chatglm.py CHANGED
@@ -40,12 +40,12 @@ class GetGLMHandle(Process):
40
  while True:
41
  try:
42
  if self.chatglm_model is None:
43
- self.chatglm_tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm2-6b", trust_remote_code=True)
44
  device, = get_conf('LOCAL_MODEL_DEVICE')
45
  if device=='cpu':
46
- self.chatglm_model = AutoModel.from_pretrained("THUDM/chatglm2-6b", trust_remote_code=True).float()
47
  else:
48
- self.chatglm_model = AutoModel.from_pretrained("THUDM/chatglm2-6b", trust_remote_code=True).half().cuda()
49
  self.chatglm_model = self.chatglm_model.eval()
50
  break
51
  else:
 
40
  while True:
41
  try:
42
  if self.chatglm_model is None:
43
+ self.chatglm_tokenizer = AutoTokenizer.from_pretrained("fb700/chatglm-fitness-RLHF", trust_remote_code=True)
44
  device, = get_conf('LOCAL_MODEL_DEVICE')
45
  if device=='cpu':
46
+ self.chatglm_model = AutoModel.from_pretrained("fb700/chatglm-fitness-RLHF", trust_remote_code=True).float()
47
  else:
48
+ self.chatglm_model = AutoModel.from_pretrained("fb700/chatglm-fitness-RLHF", trust_remote_code=True).half().quantize(8).cuda()
49
  self.chatglm_model = self.chatglm_model.eval()
50
  break
51
  else:
requirements.txt CHANGED
@@ -16,4 +16,9 @@ numpy
16
  arxiv
17
  rich
18
  pdfminer
19
- beautifulsoup4
 
 
 
 
 
 
16
  arxiv
17
  rich
18
  pdfminer
19
+ protobuf
20
+ transformers==4.27.1
21
+ cpm_kernels
22
+ torch>=1.10
23
+ mdtex2html
24
+ sentencepiece