Hi All,

Memory controller testcase1.

Signed-off-by: Sudhir Kumar <[EMAIL PROTECTED]>
Acked-by: Balbir Singh <[EMAIL PROTECTED]>


Index: ltp-full-20080229/testcases/kernel/controllers/Makefile
===================================================================
--- ltp-full-20080229.orig/testcases/kernel/controllers/Makefile
+++ ltp-full-20080229/testcases/kernel/controllers/Makefile
@@ -1,5 +1,6 @@
-SUBDIRS = libcontrollers cpuctl
+SUBDIRS = libcontrollers cpuctl memctl
 CHECK_CPUCTL = $(shell grep -w cpu /proc/cgroups|cut -f1)
+CHECK_MEMCTL = $(shell grep -w memory /proc/cgroups|cut -f1)
 all:
        @set -e;
 ifeq ($(CHECK_CPUCTL),cpu)
@@ -9,6 +10,13 @@ else
        echo "Kernel is not compiled with cpu controller support";
 endif
 
+ifeq ($(CHECK_MEMCTL),memory)
+
+       for i in $(SUBDIRS); do $(MAKE) -C $$i $@ ;done;
+else
+       echo "Kernel is not compiled with memory resource controller support";
+endif
+
 install:
        @set -e; \
         ln -f test_controllers.sh ../../bin/test_controllers.sh;
@@ -21,5 +29,13 @@ else
        echo "Kernel is not compiled with cpu controller support";
 endif
 
+ifeq ($(CHECK_MEMCTL),memory)
+
+       for i in $(SUBDIRS); do $(MAKE) -C $$i install ; done; \
+       chmod ugo+x test_controllers.sh;
+else
+       echo "Kernel is not compiled with memory resource controller support";
+endif
+
 clean:
        @set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i clean ; done
Index: ltp-full-20080229/testcases/kernel/controllers/memctl/Makefile
===================================================================
--- /dev/null
+++ ltp-full-20080229/testcases/kernel/controllers/memctl/Makefile
@@ -0,0 +1,16 @@
+CFLAGS += -Wall
+CPPFLAGS += -I../../../../include -I../libcontrollers
+LDLIBS += -lm -L../../../../lib/ -L../libcontrollers -lcontrollers -lltp
+
+SRCS    = $(wildcard *.c)
+
+TARGETS = $(patsubst %.c,%,$(SRCS))
+
+all:   $(TARGETS)
+
+clean:
+       rm -f $(TARGETS) *.o
+
+install:
+       @set -e; for i in $(TARGETS) run_memctl_test.sh myfunctions.sh; do ln 
-f $$i ../../../bin/$$i ; chmod +x $$i ; done
+
Index: ltp-full-20080229/testcases/kernel/controllers/memctl/memctl_test01.c
===================================================================
--- /dev/null
+++ ltp-full-20080229/testcases/kernel/controllers/memctl/memctl_test01.c
@@ -0,0 +1,176 @@
+/******************************************************************************/
+/*                                                                            
*/
+/* Copyright (c) International Business Machines  Corp., 2008                 
*/
+/*                                                                            
*/
+/* This program is free software;  you can redistribute it and/or modify      
*/
+/* it under the terms of the GNU General Public License as published by       
*/
+/* the Free Software Foundation; either version 2 of the License, or          
*/
+/* (at your option) any later version.                                        
*/
+/*                                                                            
*/
+/* This program is distributed in the hope that it will be useful,            
*/
+/* but WITHOUT ANY WARRANTY;  without even the implied warranty of            
*/
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                  
*/
+/* the GNU General Public License for more details.                           
*/
+/*                                                                            
*/
+/* You should have received a copy of the GNU General Public License          
*/
+/* along with this program;  if not, write to the Free Software               
*/
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA    
*/
+/*                                                                            
*/
+/******************************************************************************/
+
+/******************************************************************************/
+/*                                                                            
*/
+/* File:        memctl_test01.c                                               
*/
+/*                                                                            
*/
+/* Description: This is a c program that allocates memory in chunks of size   
*/
+/*              as given by the calling script. The program touches all the   
*/
+/*              allocated pages by writing a string on each page.             
*/
+/*                                                                            
*/
+/* Total Tests: 1                                                             
*/
+/*                                                                            
*/
+/* Test Name:   mem_controller_test01                                         
*/
+/*                                                                            
*/
+/*                                                                            
*/
+/* Test Assertion                                                             
*/
+/*              Please refer to the file memctl_testplan.txt                  
*/
+/*                                                                            
*/
+/* Author:      Sudhir Kumar [EMAIL PROTECTED]                        */
+/*                                                                            
*/
+/* History:                                                                   
*/
+/* Created      12/03/2008  Sudhir Kumar <[EMAIL PROTECTED]>          */
+/*                                                                            
*/
+/******************************************************************************/
+
+/* Standard Include Files */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "libcontrollers.h"
+#include "test.h"
+
+
+extern int Tst_count;
+char *TCID = "memory_controller_test01";
+int TST_TOTAL = 1;
+
+pid_t scriptpid;
+typedef size_t record_t;
+record_t **array_of_chunks;
+record_t tmp;
+int num_of_chunks, chunk_size, test_num, limit;
+
+extern void cleanup();
+void signal_handler_sigusr1 (int signal);
+int allocate_memory(void);
+
+int main(int argc, char *argv[])
+{
+       int ret;
+       char mygroup[FILENAME_MAX], mytaskfile[FILENAME_MAX];
+       char *mygroup_p, *script_pid_p, *test_num_p, *chunk_size_p, 
*num_chunks_p;
+       struct sigaction newaction1, oldaction1;
+
+       /* Signal handling for SIGUSR1 recieved from script */
+       sigemptyset (&newaction1.sa_mask);
+       newaction1.sa_handler = signal_handler_sigusr1;
+       newaction1.sa_flags=0;
+       sigaction (SIGUSR1, &newaction1, &oldaction1);
+
+       /*
+        *Capture variables from the script environment
+        */
+       test_num_p      = getenv("TEST_NUM");
+       mygroup_p       = getenv("MYGROUP");
+       script_pid_p    = getenv("SCRIPT_PID");
+       chunk_size_p    = getenv("CHUNK_SIZE");
+       num_chunks_p    = getenv("NUM_CHUNKS");
+
+       if ((test_num_p != NULL) && (mygroup_p != NULL) && (script_pid_p != 
NULL) && \
+               (chunk_size_p != NULL) && (num_chunks_p != NULL))
+       {
+               scriptpid       = atoi(script_pid_p);
+               test_num        = atoi(test_num_p);
+               chunk_size      = atoi(chunk_size_p);
+               num_of_chunks   = atoi(num_chunks_p);
+               sprintf(mygroup,"%s", mygroup_p);
+       }
+       else
+       {
+               tst_brkm (TBROK, cleanup, "Invalid parameters recieved from 
script\n");
+       }
+
+       sprintf(mytaskfile, "%s", mygroup);
+       strcat (mytaskfile,"/tasks");
+       /* Assign the task to it's group */
+       write_to_file (mytaskfile, "a", getpid());    /* Assign the task to 
it's group*/
+
+       ret = allocate_memory();        /*should i check ret?*/
+
+       return 0;
+}
+
+/*
+ * Function: cleanup()
+ * signals for system cleanup in case test breaks
+ */
+void cleanup()
+{
+       kill (scriptpid, SIGUSR1);/* Inform the shell to do cleanup*/
+       tst_exit ();              /* Report exit status*/
+}
+
+/*
+ * Function: signal_handler_sigusr1()
+ * signal handler for the new action
+ */
+
+void signal_handler_sigusr1 (int signal)
+{
+       int i;
+       for (i=0; i< num_of_chunks; ++i)
+               free(array_of_chunks[i]);
+       free(array_of_chunks);
+       exit (0);
+}
+
+int allocate_memory()
+{
+       int i, j;
+       /*
+        * Allocate array which contains base addresses of all chunks
+        */
+       array_of_chunks = (record_t *) malloc(sizeof(record_t *) * 
num_of_chunks);
+       if (array_of_chunks == NULL)
+               tst_brkm (TBROK, cleanup, "Memory allocation failed for 
array_of_chunks");
+       /*
+        * Allocate chunks of memory
+        */
+
+       for (i=0; i< num_of_chunks; ++i)
+       {
+               array_of_chunks[i] = (record_t *) malloc(chunk_size);
+               if (array_of_chunks[i] == NULL)
+                       tst_brkm (TBROK, cleanup, "Memory allocation failed for 
chunks. Try smaller chunk size");
+       }
+
+       /*
+        * Touch all the pages of allocated memory by writing some string
+        */
+       limit = chunk_size / sizeof(record_t);
+
+       for (i=0; i< num_of_chunks; ++i)
+               for (j=0; j< limit; ++j)
+                       array_of_chunks[i][j] = 0xaa;
+
+       /*
+        * Just keep on accessing the allocated pages and do nothing relevant
+        */
+       while (1)
+       {
+               for (i=0; i< num_of_chunks; ++i)
+                       for (j=0; j< limit; ++j)
+                               tmp = array_of_chunks[i][j];
+       }
+       return 0;
+}
Index: ltp-full-20080229/testcases/kernel/controllers/memctl/myfunctions.sh
===================================================================
--- /dev/null
+++ ltp-full-20080229/testcases/kernel/controllers/memctl/myfunctions.sh
@@ -0,0 +1,121 @@
+#!/bin/bash
+# usage ./functions.sh
+
+#################################################################################
+#  Copyright (c) International Business Machines  Corp., 2008                  
 #
+#                                                                              
 #
+#  This program is free software;  you can redistribute it and/or modify       
 #
+#  it under the terms of the GNU General Public License as published by        
 #
+#  the Free Software Foundation; either version 2 of the License, or           
 #
+#  (at your option) any later version.                                         
 #
+#                                                                              
 #
+#  This program is distributed in the hope that it will be useful,             
 #
+#  but WITHOUT ANY WARRANTY;  without even the implied warranty of             
 #
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                   
 #
+#  the GNU General Public License for more details.                            
 #
+#                                                                              
 #
+#  You should have received a copy of the GNU General Public License           
 #
+#  along with this program;  if not, write to the Free Software                
 #
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA     
 #
+#                                                                              
 #
+#################################################################################
+#  Name Of File: myfunctions.sh                                                
 #
+#                                                                              
 #
+#  Description: This file has functions for the setup for testing memory       
 #
+#               controller. setup includes creating controller device,         
 #
+#               mounting it with cgroup filesystem with option memory and      
 #
+#               creating groups in it.                                         
 #
+#                                                                              
 #
+#  Functions:   setup(): creaes /dev/memctl, mounts cgroup fs on it, creates   
 #
+#               groups in that etc.                                            
 #
+#               setmemlimits(): Sets up memory limits for different groups     
 #
+#               usage(): Shows the usage of this file.                         
 #
+#               cleanup(): Does full system cleanup                            
 #
+#                                                                              
 #
+#  Author:       Sudhir Kumar   <[EMAIL PROTECTED]>                     #
+#                                                                              
 #
+#  History:                                                                    
 #
+#                                                                              
 #
+#  DATE         NAME           EMAIL                         DESC              
 #
+#                                                                              
 #
+#  15/03/08  Sudhir Kumar <[EMAIL PROTECTED]>   Created this test       #
+#                                                                              
 #
+#################################################################################
+
+       # Write the cleanup function
+cleanup ()
+{
+       echo "Cleanup called";
+       rm -f memctl_task_* 2>/dev/null
+       rmdir /dev/memctl/group* 2> /dev/null
+       umount /dev/memctl 2> /dev/null
+       rmdir /dev/memctl 2> /dev/null
+}
+       # Create /dev/memctl &  mount the cgroup file system with memory 
controller
+       #clean any group created eralier (if any)
+
+setup ()
+{
+       if [ -e /dev/memctl ]
+       then
+               echo "WARN:/dev/memctl already exist..overwriting";
+               cleanup;
+               mkdir /dev/memctl;
+       else
+               mkdir /dev/memctl
+       fi
+       mount -t cgroup -omemory cgroup /dev/memctl 2> /dev/null
+       if [ $? -ne 0 ]
+       then
+               echo "ERROR: Could not mount cgroup filesystem on 
/dev/memctl..Exiting test";
+               cleanup;
+               exit -1;
+       fi
+
+       # Group created earlier may again be visible if not cleaned 
properly...so clean them
+       if [ -e /dev/memctl/group_1 ]
+       then
+               rmdir /dev/memctl/group*
+               echo "WARN: Earlier groups found and removed...";
+       fi
+
+       # Create different groups
+       for i in $(seq 1 $NUM_GROUPS)
+       do
+               group=group_$i;
+               mkdir /dev/memctl/$group;# 2>/dev/null
+               if [ $? -ne 0 ]
+               then
+                       echo "ERROR: Can't create $group...Check your 
permissions..Exiting test";
+                       cleanup;
+                       exit -1;
+               fi
+       done
+}
+
+# The usage of the script file
+usage()
+{
+       echo "Could not start memory controller test";
+       echo "usage: run_memctl_test.sh test_num";
+       echo "Skipping the memory controller test...";
+}
+
+# Function to set memory limits for different groups
+setmemlimits()
+{
+       for i in $(seq 1 $NUM_GROUPS)
+       do
+               limit=MEMLIMIT_GROUP_${i};
+               eval limit=\$$limit;
+               echo -n $limit >/dev/memctl/group_$i/memory.limit_in_bytes;
+               if [ $? -ne 0 ]
+               then
+                       echo "Error in setting the memory limits for group_$i"
+                       cleanup;
+                       exit -1;
+               fi;
+       done
+}
+
+
Index: ltp-full-20080229/testcases/kernel/controllers/memctl/run_memctl_test.sh
===================================================================
--- /dev/null
+++ ltp-full-20080229/testcases/kernel/controllers/memctl/run_memctl_test.sh
@@ -0,0 +1,209 @@
+#!/bin/bash
+# usage ./runmemctl_test.sh test_num
+
+#################################################################################
+#  Copyright (c) International Business Machines  Corp., 2008                  
 #
+#                                                                              
 #
+#  This program is free software;  you can redistribute it and/or modify       
 #
+#  it under the terms of the GNU General Public License as published by        
 #
+#  the Free Software Foundation; either version 2 of the License, or           
 #
+#  (at your option) any later version.                                         
 #
+#                                                                              
 #
+#  This program is distributed in the hope that it will be useful,             
 #
+#  but WITHOUT ANY WARRANTY;  without even the implied warranty of             
 #
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                   
 #
+#  the GNU General Public License for more details.                            
 #
+#                                                                              
 #
+#  You should have received a copy of the GNU General Public License           
 #
+#  along with this program;  if not, write to the Free Software                
 #
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA     
 #
+#                                                                              
 #
+#################################################################################
+# Name Of File: run_memctl_test.sh                                             
 #
+#                                                                              
 #
+# Description: This file runs the setup for testing different memory resource  
 #
+#              controller features. After setup it runs diff test cases in 
diff #
+#              setup.                                                          
 #
+#                                                                              
 #
+# Test 01:     Tests group memory usage on task migration                      
 #
+#                                                                              
 #
+# Precaution:   Avoid system use by other applications/users to get fair and   
 #
+#               appropriate results (avoid unnecessary killing of applicatio)  
 #
+#                                                                              
 #
+# Author:       Sudhir Kumar   <[EMAIL PROTECTED]>                      #
+#                                                                              
 #
+# History:                                                                     
 #
+#                                                                              
 #
+#  DATE         NAME           EMAIL                         DESC              
 #
+#                                                                              
 #
+#  12/03/08  Sudhir Kumar <[EMAIL PROTECTED]>   Created this test       #
+#                                                                              
 #
+#################################################################################
+
+export TCID="memctl_test01";
+export TST_TOTAL=1;
+export TST_COUNT=1;
+
+TEST_NUM=$1;
+SCRIPT_PID=$$;
+RC=0;
+PWD=`pwd`;
+cd $LTPROOT/testcases/bin/
+. myfunctions.sh
+#################################################################################
+#   ****************************** WARNING *********************************   
 #
+# User can change the parameters in different cases below but before doing     
 #
+# any change user is supposed to know what he is doing. At any point when      
 #
+# memory usage of a group becomes more than the group limit OOM Killer will    
 #
+# be invoked and some of the tasks will be killed. Need to add code to handle  
 #
+# the OOM Killer issues.                                                       
 #
+#################################################################################
+
+# First of all check if the system has sufficient memory
+# Checking Inactive memory is sufficient. Is'nt it??
+MEM_AVAIL=`cat /proc/meminfo | grep Inactive | tr -s [:space:] | cut -d" " 
-f2`;
+if [ $MEM_AVAIL -lt 262144 ]   # 256MB(as test requires some ~200MB)
+then
+       echo System does not have sufficient free memory.;
+       echo Skipping execution of memory controller tests.;
+       exit;
+fi
+
+case ${TEST_NUM} in
+
+"1" )  NUM_GROUPS=2;
+       MEMLIMIT_GROUP_1=100M;
+       MEMLIMIT_GROUP_2=132M;
+       CHUNK_SIZE=6291456;                             # malloc n chunks of 
size m(6M)
+       NUM_CHUNKS=10;                                  # (say)60 MB 
memory(6*10)
+       TOTAL_TASKS=1;                                  # num of tasks in a 
group(1)
+       NUM_MIG_TASKS=$TOTAL_TASKS                      # num of tasks to 
migrate
+       MEM_TASK=`expr $CHUNK_SIZE \* $NUM_CHUNKS`;     # memory allocated by a 
task
+       MEM_TOTAL=`expr $MEM_TASK \* $TOTAL_TASKS`;     # total memory 
allocated in a group
+       TEST_NAME=" TASK MIGRATION TEST:";
+       ;;
+
+*  )   usage;
+       exit -1
+               ;;
+       esac
+
+echo "TEST $TEST_NUM: MEMORY CONTROLLER TESTING";
+echo "RUNNING SETUP.....";
+setup;
+
+# Trap the signal from any abnormaly terminated task
+# and kill all others and let cleanup be called
+trap 'echo "signal caught from task"; killall memctl_task_*;\
+cleanup; exit -1;' SIGUSR1;#??? may need changes here
+
+echo "TEST STARTED: Please avoid using system while this test executes";
+#Check if  C source  file has been compiled and then run it in different groups
+
+case $TEST_NUM in
+"1")
+       setmemlimits;
+       if [ -f memctl_test01 ]
+       then
+               for i in $(seq 1 $TOTAL_TASKS)
+               do
+                       MYGROUP=/dev/memctl/group_1;
+                       cp memctl_test01 memctl_task_$i # 2>/dev/null;
+                       chmod +x memctl_task_$i;
+                       TEST_NUM=$TEST_NUM MYGROUP=$MYGROUP 
SCRIPT_PID=$SCRIPT_PID CHUNK_SIZE=$CHUNK_SIZE \
+                               NUM_CHUNKS=$NUM_CHUNKS ./memctl_task_$i &
+                       if [ $? -ne 0 ]
+                       then
+                               echo "Error: Could not run ./memctl_task_$i"
+                               cleanup;
+                               exit -1;
+                       else
+                               PID[$i]=$!;
+                       fi
+               done;   # tasks are now running in group1
+
+               # Wait untill tasks allocate memory from group1
+               while [ 1 -gt 0 ]
+               do
+                       sleep 1;
+                       GRP1_MEMUSAGE=`cat 
/dev/memctl/group_1/memory.usage_in_bytes`;
+                       if [ $GRP1_MEMUSAGE -gt $MEM_TOTAL ]
+                       then
+                               break;
+                       fi
+               done
+               GRP2_MEMUSAGE_OLD=`cat 
/dev/memctl/group_2/memory.usage_in_bytes`;
+               echo Before task migration to group2
+               echo group2 memory usage: $GRP2_MEMUSAGE_OLD Bytes
+
+               # Now migrate the tasks to another group
+               for i in $(seq 1 $NUM_MIG_TASKS)
+               do
+                       echo ${PID[$i]} >>/dev/memctl/group_2/tasks;
+                       if [ $? -ne 0 ]
+                       then
+                               echo "TFAIL Task migration failed from group_1 
to group_2";
+                       fi
+               done
+
+               # double check
+               GRP2_TASKS=`cat /dev/memctl/group_2/tasks|wc -l`;
+               if [ $GRP2_TASKS -ne $NUM_MIG_TASKS ]
+               then
+                       echo "TFAIL Task Migration failed for some of the 
tasks";
+               fi;
+
+               # Wait for some time to check if memory usage of group_2 
increases
+               # This is not the right approach however working. ??? 
thoughts???
+               sleep 10;
+               GRP2_MEMUSAGE_NEW=`cat 
/dev/memctl/group_2/memory.usage_in_bytes`;
+               echo After task migration to group2
+               echo group2 memory usage: $GRP2_MEMUSAGE_NEW Bytes
+
+               # Decision formula: decides PASS or FAIL
+               if [ $GRP2_MEMUSAGE_NEW -gt $GRP2_MEMUSAGE_OLD ]
+               then
+                       echo "TFAIL   Memory resource Controller:  Task 
Migration test FAILED";
+               else
+                       echo "TPASS   Memory Resource Controller: Task 
Migration test PASSED";
+               fi
+
+                       # here we can add another testcases
+
+                       # Now we can signal the task to finish and do the 
cleanup
+               for i in $(seq 1 $TOTAL_TASKS)
+               do
+                       kill -SIGUSR1 ${PID[$i]};
+               done
+       else
+               echo "Source file not compiled..Plz check Makefile...Exiting 
test"
+               cleanup;
+               exit -1;
+       fi;
+       ;;
+
+       "*" )
+               usage;
+               exit -1;
+               ;;
+       esac
+
+       for i in $(seq 1 $TOTAL_TASKS)
+       do
+               wait ${PID[$i]};
+               RC=$?;  # Return status of the task being waited
+               # In abnormal termination of anyone trap will kill all others
+               # and they will return non zero exit status. So Test broke!!
+               if [ $RC -ne 0 ]
+               then
+                       echo "Task $i exited abnormaly with return value: $RC";
+                       tst_resm TINFO "Test could not execute for the expected 
duration";
+                       cleanup;
+                       exit -1;
+               fi
+       done
+
+       echo "Memory Resource Controller test executed successfully.";
+       cleanup;
+       cd $PWD
+       exit 0;         #to let PAN reprt success of test
Index: ltp-full-20080229/testcases/kernel/controllers/test_controllers.sh
===================================================================
--- ltp-full-20080229.orig/testcases/kernel/controllers/test_controllers.sh
+++ ltp-full-20080229/testcases/kernel/controllers/test_controllers.sh
@@ -37,6 +37,8 @@
 if [ -f /proc/cgroups ]
 then
        CPU_CONTROLLER=`grep -w cpu /proc/cgroups | cut -f1`;
+       MEM_CONTROLLER=`grep -w memory /proc/cgroups | cut -f1`;
+
        if [ "$CPU_CONTROLLER" = "cpu" ]
        then
                $LTPROOT/testcases/bin/run_cpuctl_test.sh 1;
@@ -48,10 +50,20 @@ then
                $LTPROOT/testcases/bin/run_cpuctl_stress_test.sh 8;
                $LTPROOT/testcases/bin/run_cpuctl_stress_test.sh 9;
                $LTPROOT/testcases/bin/run_cpuctl_stress_test.sh 10;
+               echo
        else
                echo "CONTROLLERS TESTCASES: WARNING";
                echo "Kernel does not support for cpu controller";
                echo "Skipping all cpu controller testcases....";
+       fi;
+
+       if [ "$MEM_CONTROLLER" = "memory" ]
+       then
+               $LTPROOT/testcases/bin/run_memctl_test.sh 1;
+       else
+               echo "CONTROLLERS TESTCASES: WARNING";
+               echo "Kernel does not support for memory controller";
+               echo "Skipping all memory controller testcases....";
        fi
 else
        echo "CONTROLLERS TESTCASES: WARNING"


Regards 
Sudhir

-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone
_______________________________________________
Ltp-list mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ltp-list

Reply via email to