Skip to content

Commit 54cf9e5

Browse files
committed
Ticket [ecf13be4c9] Multi interpreter solution
1 parent 7d6679b commit 54cf9e5

File tree

1 file changed

+112
-34
lines changed

1 file changed

+112
-34
lines changed

generic/tclsample.c

Lines changed: 112 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,23 @@
2828
static const unsigned char itoa64f[] =
2929
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_,";
3030

31-
static int numcontexts = 0;
32-
static SHA1_CTX *sha1Contexts = NULL;
33-
static Tcl_Size *ctxtotalRead = NULL;
31+
#define DIGESTSIZE 20
32+
33+
/*
34+
* The procedure needs interpreter local state. This is called
35+
* "Command client data" in TCL. Typically, a struct is allocated and
36+
* the pointer to it is made available on each operation by TCL.
37+
* Here is the struct for the sha1 procedure.
38+
*/
39+
40+
struct Sha1ClientData {
41+
int numcontexts;
42+
SHA1_CTX *sha1Contexts;
43+
Tcl_Size *ctxtotalRead;
44+
};
3445

3546
static int Sha1_Cmd(void *clientData, Tcl_Interp *interp,
3647
int objc, Tcl_Obj *const objv[]);
37-
38-
#define DIGESTSIZE 20
3948

4049
/*
4150
*----------------------------------------------------------------------
@@ -55,12 +64,18 @@ static int Sha1_Cmd(void *clientData, Tcl_Interp *interp,
5564

5665
static int
5766
Sha1_Cmd(
58-
void *dummy, /* Not used. */
67+
ClientData clientData, /* Client data with thread local state */
5968
Tcl_Interp *interp, /* Current interpreter */
6069
int objc, /* Number of arguments */
6170
Tcl_Obj *const objv[] /* Argument strings */
6271
)
6372
{
73+
/*
74+
* Get my thread local memory
75+
*/
76+
77+
struct Sha1ClientData *sha1ClientDataPtr = clientData;
78+
6479
/*
6580
* The default base is hex
6681
*/
@@ -72,15 +87,13 @@ Sha1_Cmd(
7287
Tcl_Channel copychan = NULL;
7388
int mode;
7489
int contextnum = 0;
75-
#define sha1Context (sha1Contexts[contextnum])
7690
char *bufPtr;
7791
Tcl_WideInt maxbytes = 0;
7892
int doinit = 1;
7993
int dofinal = 1;
8094
Tcl_Obj *descriptorObj = NULL;
8195
Tcl_Size totalRead = 0, n;
8296
int i, j, mask, bits, offset;
83-
(void)dummy;
8497

8598
/*
8699
* For binary representation + null char
@@ -113,24 +126,26 @@ Sha1_Cmd(
113126
}
114127
switch ((enum ShaOpts) index) {
115128
case SHAOPT_INIT:
116-
for (contextnum = 1; contextnum < numcontexts; contextnum++) {
117-
if (ctxtotalRead[contextnum] == -1) {
129+
for (contextnum = 1; contextnum < sha1ClientDataPtr->numcontexts; contextnum++) {
130+
if (sha1ClientDataPtr->ctxtotalRead[contextnum] == -1) {
118131
break;
119132
}
120133
}
121-
if (contextnum == numcontexts) {
134+
if (contextnum == sha1ClientDataPtr->numcontexts) {
122135
/*
123136
* Allocate a new context.
124137
*/
125138

126-
numcontexts++;
127-
sha1Contexts = (SHA1_CTX *) ckrealloc((void *) sha1Contexts,
128-
numcontexts * sizeof(SHA1_CTX));
129-
ctxtotalRead = (Tcl_Size *)ckrealloc(ctxtotalRead,
130-
numcontexts * sizeof(Tcl_Size));
139+
sha1ClientDataPtr->numcontexts++;
140+
sha1ClientDataPtr->sha1Contexts = (SHA1_CTX *) ckrealloc(
141+
(void *) sha1ClientDataPtr->sha1Contexts,
142+
sha1ClientDataPtr->numcontexts * sizeof(SHA1_CTX));
143+
sha1ClientDataPtr->ctxtotalRead = (Tcl_Size *)ckrealloc(
144+
sha1ClientDataPtr->ctxtotalRead,
145+
sha1ClientDataPtr->numcontexts * sizeof(Tcl_Size));
131146
}
132-
ctxtotalRead[contextnum] = 0;
133-
SHA1Init(&sha1Context);
147+
sha1ClientDataPtr->ctxtotalRead[contextnum] = 0;
148+
SHA1Init(&sha1ClientDataPtr->sha1Contexts[contextnum]);
134149
snprintf(buf, sizeof(buf), "sha1%d", contextnum);
135150
Tcl_AppendResult(interp, buf, NULL);
136151
return TCL_OK;
@@ -188,16 +203,16 @@ Sha1_Cmd(
188203

189204
if (descriptorObj != NULL) {
190205
if ((sscanf(Tcl_GetString(descriptorObj), "sha1%d",
191-
&contextnum) != 1) || (contextnum >= numcontexts) ||
192-
(ctxtotalRead[contextnum] == -1)) {
206+
&contextnum) != 1) || (contextnum >= sha1ClientDataPtr->numcontexts) ||
207+
(sha1ClientDataPtr->ctxtotalRead[contextnum] == -1)) {
193208
Tcl_AppendResult(interp, "invalid sha1 descriptor \"",
194209
Tcl_GetString(descriptorObj), "\"", NULL);
195210
return TCL_ERROR;
196211
}
197212
}
198213

199214
if (doinit) {
200-
SHA1Init(&sha1Context);
215+
SHA1Init(&sha1ClientDataPtr->sha1Contexts[contextnum]);
201216
}
202217

203218
if (stringObj != NULL) {
@@ -206,10 +221,17 @@ Sha1_Cmd(
206221
goto wrongArgs;
207222
}
208223
string = Tcl_GetStringFromObj(stringObj, &totalRead);
209-
SHA1Update(&sha1Context, (unsigned char *) string, totalRead);
224+
SHA1Update(&sha1ClientDataPtr->sha1Contexts[contextnum],
225+
(unsigned char *) string, totalRead);
210226
} else if (chan != NULL) {
211227
bufPtr = (char *)ckalloc(TCL_READ_CHUNK_SIZE);
212228
totalRead = 0;
229+
/*
230+
* FIXME: MS-VC 2015 gives the following warning in the next line I
231+
* was not able to fix (translated from German):
232+
* warning C4244: "Function": Conversion of "Tcl_WideInt" to "int",
233+
* possible data loss
234+
*/
213235
while ((n = Tcl_Read(chan, bufPtr,
214236
maxbytes == 0
215237
? TCL_READ_CHUNK_SIZE
@@ -226,7 +248,8 @@ Sha1_Cmd(
226248

227249
totalRead += n;
228250

229-
SHA1Update(&sha1Context, (unsigned char *) bufPtr, n);
251+
SHA1Update(&sha1ClientDataPtr->sha1Contexts[contextnum],
252+
(unsigned char *) bufPtr, n);
230253

231254
if (copychan != NULL) {
232255
n = Tcl_Write(copychan, bufPtr, n);
@@ -250,17 +273,17 @@ Sha1_Cmd(
250273
}
251274

252275
if (!dofinal) {
253-
ctxtotalRead[contextnum] += totalRead;
276+
sha1ClientDataPtr->ctxtotalRead[contextnum] += totalRead;
254277
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(totalRead));
255278
return TCL_OK;
256279
}
257280

258281
if (stringObj == NULL) {
259-
totalRead += ctxtotalRead[contextnum];
282+
totalRead += sha1ClientDataPtr->ctxtotalRead[contextnum];
260283
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(totalRead));
261284
}
262285

263-
SHA1Final(&sha1Context, digest);
286+
SHA1Final(&sha1ClientDataPtr->sha1Contexts[contextnum], digest);
264287

265288
/*
266289
* Take the 20 byte array and print it in the requested base
@@ -297,7 +320,7 @@ Sha1_Cmd(
297320
buf[j++] = '\0';
298321
Tcl_AppendResult(interp, buf, NULL);
299322
if (contextnum > 0) {
300-
ctxtotalRead[contextnum] = -1;
323+
sha1ClientDataPtr->ctxtotalRead[contextnum] = -1;
301324
}
302325
return TCL_OK;
303326

@@ -325,6 +348,42 @@ Sha1_Cmd(
325348
NULL);
326349
return TCL_ERROR;
327350
}
351+
352+
353+
/*
354+
*----------------------------------------------------------------------
355+
*
356+
* Sha1_CmdDeleteProc --
357+
*
358+
* Clear all thread data of the Sha1 command.
359+
*
360+
* Results:
361+
* No result
362+
*
363+
* Side effects:
364+
* None.
365+
*
366+
*----------------------------------------------------------------------
367+
*/
368+
369+
static void
370+
Sha1_CmdDeleteProc(ClientData clientData)
371+
{
372+
struct Sha1ClientData *sha1ClientDataPtr = clientData;
373+
374+
/*
375+
* Release the sha1 contextes
376+
*/
377+
378+
ckfree(sha1ClientDataPtr->sha1Contexts);
379+
ckfree(sha1ClientDataPtr->ctxtotalRead);
380+
381+
/*
382+
* Release the procedure client data
383+
*/
384+
385+
ckfree(sha1ClientDataPtr);
386+
}
328387

329388
/*
330389
*----------------------------------------------------------------------
@@ -358,6 +417,7 @@ Sample_Init(
358417
Tcl_Interp* interp) /* Tcl interpreter */
359418
{
360419
Tcl_CmdInfo info;
420+
struct Sha1ClientData *sha1ClientDataPtr;
361421

362422
/*
363423
* Require compatible TCL version.
@@ -368,10 +428,35 @@ Sample_Init(
368428
* Note that Tcl_InitStubs is a macro, which is replaced by a Tcl version
369429
* check only, if TCL_STUBS is not defined (e.g. direct link, static build)
370430
*/
431+
371432
if (Tcl_InitStubs(interp, "8.1-", 0) == NULL) {
372433
return TCL_ERROR;
373434
}
374435

436+
/*
437+
* Init the sha1 context queues
438+
*/
439+
440+
sha1ClientDataPtr = ckalloc(sizeof(struct Sha1ClientData));
441+
sha1ClientDataPtr->numcontexts = 1;
442+
sha1ClientDataPtr->sha1Contexts = (SHA1_CTX *) ckalloc(sizeof(SHA1_CTX));
443+
sha1ClientDataPtr->ctxtotalRead = (Tcl_Size *) ckalloc(sizeof(Tcl_Size));
444+
445+
/*
446+
* Create the sha1 command.
447+
* Pass the client data pointer to the procedure, so the queue data is
448+
* available.
449+
* Also, register a delete proc to clear the sha1 queue on deletion.
450+
*/
451+
452+
Tcl_CreateObjCommand(
453+
interp, "sha1", (Tcl_ObjCmdProc *)Sha1_Cmd,
454+
sha1ClientDataPtr, Sha1_CmdDeleteProc);
455+
456+
/*
457+
* Create the buildinfo command if tcl supports it
458+
*/
459+
375460
if (Tcl_GetCommandInfo(interp, "::tcl::build-info", &info)) {
376461
Tcl_CreateObjCommand(interp, "::sample::build-info",
377462
info.objProc, (void *)(
@@ -434,13 +519,6 @@ Sample_Init(
434519
if (Tcl_PkgProvideEx(interp, PACKAGE_NAME, PACKAGE_VERSION, NULL) != TCL_OK) {
435520
return TCL_ERROR;
436521
}
437-
Tcl_CreateObjCommand(interp, "sha1", (Tcl_ObjCmdProc *)Sha1_Cmd,
438-
NULL, NULL);
439-
440-
numcontexts = 1;
441-
sha1Contexts = (SHA1_CTX *) ckalloc(sizeof(SHA1_CTX));
442-
ctxtotalRead = (Tcl_Size *) ckalloc(sizeof(Tcl_Size));
443-
ctxtotalRead[0] = 0;
444522

445523
return TCL_OK;
446524
}

0 commit comments

Comments
 (0)